akka-core now compiles
This commit is contained in:
parent
2ea646db74
commit
d396961f76
52 changed files with 755 additions and 1100 deletions
|
|
@ -7,7 +7,8 @@ package se.scalablesolutions.akka.amqp
|
||||||
import com.rabbitmq.client.{AMQP => RabbitMQ, _}
|
import com.rabbitmq.client.{AMQP => RabbitMQ, _}
|
||||||
import com.rabbitmq.client.ConnectionFactory
|
import com.rabbitmq.client.ConnectionFactory
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.{Actor, ActorID}
|
||||||
|
import se.scalablesolutions.akka.actor.Actor._
|
||||||
import se.scalablesolutions.akka.config.OneForOneStrategy
|
import se.scalablesolutions.akka.config.OneForOneStrategy
|
||||||
import se.scalablesolutions.akka.config.ScalaConfig._
|
import se.scalablesolutions.akka.config.ScalaConfig._
|
||||||
import se.scalablesolutions.akka.util.{HashCode, Logging}
|
import se.scalablesolutions.akka.util.{HashCode, Logging}
|
||||||
|
|
@ -50,7 +51,7 @@ object AMQP {
|
||||||
exchangeName: String,
|
exchangeName: String,
|
||||||
returnListener: Option[ReturnListener],
|
returnListener: Option[ReturnListener],
|
||||||
shutdownListener: Option[ShutdownListener],
|
shutdownListener: Option[ShutdownListener],
|
||||||
initReconnectDelay: Long) =
|
initReconnectDelay: Long): ActorID =
|
||||||
supervisor.newProducer(
|
supervisor.newProducer(
|
||||||
config, hostname, port, exchangeName, returnListener, shutdownListener, initReconnectDelay)
|
config, hostname, port, exchangeName, returnListener, shutdownListener, initReconnectDelay)
|
||||||
|
|
||||||
|
|
@ -65,7 +66,7 @@ object AMQP {
|
||||||
passive: Boolean,
|
passive: Boolean,
|
||||||
durable: Boolean,
|
durable: Boolean,
|
||||||
autoDelete: Boolean,
|
autoDelete: Boolean,
|
||||||
configurationArguments: Map[String, AnyRef]) =
|
configurationArguments: Map[String, AnyRef]): ActorID =
|
||||||
supervisor.newConsumer(
|
supervisor.newConsumer(
|
||||||
config, hostname, port, exchangeName, exchangeType,
|
config, hostname, port, exchangeName, exchangeType,
|
||||||
shutdownListener, initReconnectDelay,
|
shutdownListener, initReconnectDelay,
|
||||||
|
|
@ -92,14 +93,14 @@ object AMQP {
|
||||||
exchangeName: String,
|
exchangeName: String,
|
||||||
returnListener: Option[ReturnListener],
|
returnListener: Option[ReturnListener],
|
||||||
shutdownListener: Option[ShutdownListener],
|
shutdownListener: Option[ShutdownListener],
|
||||||
initReconnectDelay: Long): Producer = {
|
initReconnectDelay: Long): ActorID = {
|
||||||
val producer = new Producer(
|
val producer = newActor(() => new Producer(
|
||||||
new ConnectionFactory(config),
|
new ConnectionFactory(config),
|
||||||
hostname, port,
|
hostname, port,
|
||||||
exchangeName,
|
exchangeName,
|
||||||
returnListener,
|
returnListener,
|
||||||
shutdownListener,
|
shutdownListener,
|
||||||
initReconnectDelay)
|
initReconnectDelay))
|
||||||
startLink(producer)
|
startLink(producer)
|
||||||
producer
|
producer
|
||||||
}
|
}
|
||||||
|
|
@ -115,8 +116,8 @@ object AMQP {
|
||||||
passive: Boolean,
|
passive: Boolean,
|
||||||
durable: Boolean,
|
durable: Boolean,
|
||||||
autoDelete: Boolean,
|
autoDelete: Boolean,
|
||||||
configurationArguments: Map[String, AnyRef]): Consumer = {
|
configurationArguments: Map[String, AnyRef]): ActorID = {
|
||||||
val consumer = new Consumer(
|
val consumer = newActor(() => new Consumer(
|
||||||
new ConnectionFactory(config),
|
new ConnectionFactory(config),
|
||||||
hostname, port,
|
hostname, port,
|
||||||
exchangeName,
|
exchangeName,
|
||||||
|
|
@ -126,7 +127,7 @@ object AMQP {
|
||||||
passive,
|
passive,
|
||||||
durable,
|
durable,
|
||||||
autoDelete,
|
autoDelete,
|
||||||
configurationArguments)
|
configurationArguments))
|
||||||
startLink(consumer)
|
startLink(consumer)
|
||||||
consumer
|
consumer
|
||||||
}
|
}
|
||||||
|
|
@ -188,11 +189,11 @@ object AMQP {
|
||||||
val exclusive: Boolean,
|
val exclusive: Boolean,
|
||||||
val autoDelete: Boolean,
|
val autoDelete: Boolean,
|
||||||
val isUsingExistingQueue: Boolean,
|
val isUsingExistingQueue: Boolean,
|
||||||
val actor: Actor) extends AMQPMessage {
|
val actor: ActorID) extends AMQPMessage {
|
||||||
/**
|
/**
|
||||||
* Creates a non-exclusive, non-autodelete message listener.
|
* Creates a non-exclusive, non-autodelete message listener.
|
||||||
*/
|
*/
|
||||||
def this(queueName: String, routingKey: String, actor: Actor) = this (queueName, routingKey, false, false, false, actor)
|
def this(queueName: String, routingKey: String, actor: ActorID) = this (queueName, routingKey, false, false, false, actor)
|
||||||
|
|
||||||
private[akka] var tag: Option[String] = None
|
private[akka] var tag: Option[String] = None
|
||||||
|
|
||||||
|
|
@ -241,12 +242,12 @@ object AMQP {
|
||||||
exclusive: Boolean,
|
exclusive: Boolean,
|
||||||
autoDelete: Boolean,
|
autoDelete: Boolean,
|
||||||
isUsingExistingQueue: Boolean,
|
isUsingExistingQueue: Boolean,
|
||||||
actor: Actor) =
|
actor: ActorID) =
|
||||||
new MessageConsumerListener(queueName, routingKey, exclusive, autoDelete, isUsingExistingQueue, actor)
|
new MessageConsumerListener(queueName, routingKey, exclusive, autoDelete, isUsingExistingQueue, actor)
|
||||||
|
|
||||||
def apply(queueName: String,
|
def apply(queueName: String,
|
||||||
routingKey: String,
|
routingKey: String,
|
||||||
actor: Actor) =
|
actor: ActorID) =
|
||||||
new MessageConsumerListener(queueName, routingKey, false, false, false, actor)
|
new MessageConsumerListener(queueName, routingKey, false, false, false, actor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import org.apache.camel.{Processor, ExchangePattern, Exchange, ProducerTemplate}
|
||||||
import org.apache.camel.impl.DefaultExchange
|
import org.apache.camel.impl.DefaultExchange
|
||||||
import org.apache.camel.spi.Synchronization
|
import org.apache.camel.spi.Synchronization
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.{Actor, ActorID}
|
||||||
import se.scalablesolutions.akka.dispatch.CompletableFuture
|
import se.scalablesolutions.akka.dispatch.CompletableFuture
|
||||||
import se.scalablesolutions.akka.util.Logging
|
import se.scalablesolutions.akka.util.Logging
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ trait Producer { self: Actor =>
|
||||||
*/
|
*/
|
||||||
class ProducerResponseSender(
|
class ProducerResponseSender(
|
||||||
headers: Map[String, Any],
|
headers: Map[String, Any],
|
||||||
replyTo : Option[Either[Actor,CompletableFuture[Any]]],
|
replyTo : Option[Either[ActorID, CompletableFuture[Any]]],
|
||||||
producer: Actor) extends Synchronization with Logging {
|
producer: Actor) extends Synchronization with Logging {
|
||||||
|
|
||||||
implicit val producerActor = Some(producer) // the response sender
|
implicit val producerActor = Some(producer) // the response sender
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import java.util.concurrent.TimeoutException
|
||||||
import org.apache.camel.{Exchange, Consumer, Processor}
|
import org.apache.camel.{Exchange, Consumer, Processor}
|
||||||
import org.apache.camel.impl.{DefaultProducer, DefaultEndpoint, DefaultComponent}
|
import org.apache.camel.impl.{DefaultProducer, DefaultEndpoint, DefaultComponent}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.{ActorRegistry, Actor}
|
import se.scalablesolutions.akka.actor.{ActorRegistry, Actor, ActorID}
|
||||||
import se.scalablesolutions.akka.camel.{Failure, CamelMessageConversion, Message}
|
import se.scalablesolutions.akka.camel.{Failure, CamelMessageConversion, Message}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -106,7 +106,7 @@ class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) {
|
||||||
* Send the exchange in-message to the given actor using the ! operator. The message
|
* Send the exchange in-message to the given actor using the ! operator. The message
|
||||||
* send to the actor is of type se.scalablesolutions.akka.camel.Message.
|
* send to the actor is of type se.scalablesolutions.akka.camel.Message.
|
||||||
*/
|
*/
|
||||||
protected def processInOnly(exchange: Exchange, actor: Actor): Unit =
|
protected def processInOnly(exchange: Exchange, actor: ActorID): Unit =
|
||||||
actor ! exchange.toRequestMessage(Map(Message.MessageExchangeId -> exchange.getExchangeId))
|
actor ! exchange.toRequestMessage(Map(Message.MessageExchangeId -> exchange.getExchangeId))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,7 +114,7 @@ class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) {
|
||||||
* out-message is populated from the actor's reply message. The message sent to the
|
* out-message is populated from the actor's reply message. The message sent to the
|
||||||
* actor is of type se.scalablesolutions.akka.camel.Message.
|
* actor is of type se.scalablesolutions.akka.camel.Message.
|
||||||
*/
|
*/
|
||||||
protected def processInOut(exchange: Exchange, actor: Actor) {
|
protected def processInOut(exchange: Exchange, actor: ActorID) {
|
||||||
val header = Map(Message.MessageExchangeId -> exchange.getExchangeId)
|
val header = Map(Message.MessageExchangeId -> exchange.getExchangeId)
|
||||||
val result: Any = actor !! exchange.toRequestMessage(header)
|
val result: Any = actor !! exchange.toRequestMessage(header)
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def target: Option[Actor] =
|
private def target: Option[ActorID] =
|
||||||
if (ep.id.isDefined) targetById(ep.id.get)
|
if (ep.id.isDefined) targetById(ep.id.get)
|
||||||
else targetByUuid(ep.uuid.get)
|
else targetByUuid(ep.uuid.get)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package se.scalablesolutions.akka.camel.service
|
package se.scalablesolutions.akka.camel.service
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.ActorRegistry
|
import se.scalablesolutions.akka.actor.ActorRegistry
|
||||||
|
import se.scalablesolutions.akka.actor.Actor._
|
||||||
import se.scalablesolutions.akka.camel.CamelContextManager
|
import se.scalablesolutions.akka.camel.CamelContextManager
|
||||||
import se.scalablesolutions.akka.util.{Bootable, Logging}
|
import se.scalablesolutions.akka.util.{Bootable, Logging}
|
||||||
|
|
||||||
|
|
@ -17,11 +18,10 @@ import se.scalablesolutions.akka.util.{Bootable, Logging}
|
||||||
*/
|
*/
|
||||||
trait CamelService extends Bootable with Logging {
|
trait CamelService extends Bootable with Logging {
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor.Sender.Self
|
|
||||||
import CamelContextManager._
|
import CamelContextManager._
|
||||||
|
|
||||||
private[camel] val consumerPublisher = new ConsumerPublisher
|
private[camel] val consumerPublisher = newActor[ConsumerPublisher]
|
||||||
private[camel] val publishRequestor = new PublishRequestor(consumerPublisher)
|
private[camel] val publishRequestor = newActor(() => new PublishRequestor(consumerPublisher))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the CamelService. Any started actor that is a consumer actor will be (asynchronously)
|
* Starts the CamelService. Any started actor that is a consumer actor will be (asynchronously)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
import org.apache.camel.builder.RouteBuilder
|
import org.apache.camel.builder.RouteBuilder
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.{ActorUnregistered, ActorRegistered, Actor}
|
import se.scalablesolutions.akka.actor.{ActorUnregistered, ActorRegistered, Actor, ActorID}
|
||||||
import se.scalablesolutions.akka.actor.annotation.consume
|
import se.scalablesolutions.akka.actor.annotation.consume
|
||||||
import se.scalablesolutions.akka.camel.{Consumer, CamelContextManager}
|
import se.scalablesolutions.akka.camel.{Consumer, CamelContextManager}
|
||||||
import se.scalablesolutions.akka.util.Logging
|
import se.scalablesolutions.akka.util.Logging
|
||||||
|
|
@ -81,7 +81,7 @@ class ConsumerRoute(val endpointUri: String, id: String, uuid: Boolean) extends
|
||||||
*
|
*
|
||||||
* @author Martin Krasser
|
* @author Martin Krasser
|
||||||
*/
|
*/
|
||||||
class PublishRequestor(consumerPublisher: Actor) extends Actor {
|
class PublishRequestor(consumerPublisher: ActorID) extends Actor {
|
||||||
protected def receive = {
|
protected def receive = {
|
||||||
case ActorUnregistered(actor) => { /* ignore */ }
|
case ActorUnregistered(actor) => { /* ignore */ }
|
||||||
case ActorRegistered(actor) => Publish.forConsumer(actor) match {
|
case ActorRegistered(actor) => Publish.forConsumer(actor) match {
|
||||||
|
|
@ -112,24 +112,24 @@ object Publish {
|
||||||
* Creates a list of Publish request messages for all consumer actors in the <code>actors</code>
|
* Creates a list of Publish request messages for all consumer actors in the <code>actors</code>
|
||||||
* list.
|
* list.
|
||||||
*/
|
*/
|
||||||
def forConsumers(actors: List[Actor]): List[Publish] =
|
def forConsumers(actors: List[ActorID]): List[Publish] =
|
||||||
for (actor <- actors; pub = forConsumer(actor); if pub.isDefined) yield pub.get
|
for (actor <- actors; pub = forConsumer(actor); if pub.isDefined) yield pub.get
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Publish request message if <code>actor</code> is a consumer actor.
|
* Creates a Publish request message if <code>actor</code> is a consumer actor.
|
||||||
*/
|
*/
|
||||||
def forConsumer(actor: Actor): Option[Publish] =
|
def forConsumer(actor: ActorID): Option[Publish] =
|
||||||
forConsumeAnnotated(actor) orElse forConsumerType(actor)
|
forConsumeAnnotated(actor) orElse forConsumerType(actor)
|
||||||
|
|
||||||
private def forConsumeAnnotated(actor: Actor): Option[Publish] = {
|
private def forConsumeAnnotated(actor: ActorID): Option[Publish] = {
|
||||||
val annotation = actor.getClass.getAnnotation(classOf[consume])
|
val annotation = actor.getClass.getAnnotation(classOf[consume])
|
||||||
if (annotation eq null) None
|
if (annotation eq null) None
|
||||||
else if (actor._remoteAddress.isDefined) None // do not publish proxies
|
else if (actor.remoteAddress.isDefined) None // do not publish proxies
|
||||||
else Some(Publish(annotation.value, actor.getId, false))
|
else Some(Publish(annotation.value, actor.getId, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def forConsumerType(actor: Actor): Option[Publish] =
|
private def forConsumerType(actor: ActorID): Option[Publish] =
|
||||||
if (!actor.isInstanceOf[Consumer]) None
|
if (!actor.isInstanceOf[Consumer]) None
|
||||||
else if (actor._remoteAddress.isDefined) None
|
else if (actor.remoteAddress.isDefined) None
|
||||||
else Some(Publish(actor.asInstanceOf[Consumer].endpointUri, actor.uuid, true))
|
else Some(Publish(actor.asInstanceOf[Consumer].endpointUri, actor.uuid, true))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import org.apache.camel.component.mock.MockEndpoint
|
||||||
import org.scalatest.{GivenWhenThen, BeforeAndAfterEach, BeforeAndAfterAll, FeatureSpec}
|
import org.scalatest.{GivenWhenThen, BeforeAndAfterEach, BeforeAndAfterAll, FeatureSpec}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.{Actor, ActorRegistry}
|
import se.scalablesolutions.akka.actor.{Actor, ActorRegistry}
|
||||||
import se.scalablesolutions.akka.actor.Actor.Sender.Self
|
import se.scalablesolutions.akka.actor.Actor._
|
||||||
|
|
||||||
class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach with GivenWhenThen {
|
class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach with GivenWhenThen {
|
||||||
override protected def beforeAll = {
|
override protected def beforeAll = {
|
||||||
|
|
@ -27,7 +27,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
|
||||||
|
|
||||||
scenario("produce message sync and receive response") {
|
scenario("produce message sync and receive response") {
|
||||||
given("a registered synchronous two-way producer for endpoint direct:producer-test-2")
|
given("a registered synchronous two-way producer for endpoint direct:producer-test-2")
|
||||||
val producer = new TestProducer("direct:producer-test-2") with Sync
|
val producer = newActor(() => new TestProducer("direct:producer-test-2") with Sync)
|
||||||
producer.start
|
producer.start
|
||||||
|
|
||||||
when("a test message is sent to the producer")
|
when("a test message is sent to the producer")
|
||||||
|
|
@ -41,7 +41,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
|
||||||
|
|
||||||
scenario("produce message async and receive response") {
|
scenario("produce message async and receive response") {
|
||||||
given("a registered asynchronous two-way producer for endpoint direct:producer-test-2")
|
given("a registered asynchronous two-way producer for endpoint direct:producer-test-2")
|
||||||
val producer = new TestProducer("direct:producer-test-2")
|
val producer = newActor(() => new TestProducer("direct:producer-test-2"))
|
||||||
producer.start
|
producer.start
|
||||||
|
|
||||||
when("a test message is sent to the producer")
|
when("a test message is sent to the producer")
|
||||||
|
|
@ -55,7 +55,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
|
||||||
|
|
||||||
scenario("produce message sync and receive failure") {
|
scenario("produce message sync and receive failure") {
|
||||||
given("a registered synchronous two-way producer for endpoint direct:producer-test-2")
|
given("a registered synchronous two-way producer for endpoint direct:producer-test-2")
|
||||||
val producer = new TestProducer("direct:producer-test-2") with Sync
|
val producer = newActor(() => new TestProducer("direct:producer-test-2") with Sync)
|
||||||
producer.start
|
producer.start
|
||||||
|
|
||||||
when("a fail message is sent to the producer")
|
when("a fail message is sent to the producer")
|
||||||
|
|
@ -71,7 +71,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
|
||||||
|
|
||||||
scenario("produce message async and receive failure") {
|
scenario("produce message async and receive failure") {
|
||||||
given("a registered asynchronous two-way producer for endpoint direct:producer-test-2")
|
given("a registered asynchronous two-way producer for endpoint direct:producer-test-2")
|
||||||
val producer = new TestProducer("direct:producer-test-2")
|
val producer = newActor(() => new TestProducer("direct:producer-test-2"))
|
||||||
producer.start
|
producer.start
|
||||||
|
|
||||||
when("a fail message is sent to the producer")
|
when("a fail message is sent to the producer")
|
||||||
|
|
@ -87,7 +87,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
|
||||||
|
|
||||||
scenario("produce message sync oneway") {
|
scenario("produce message sync oneway") {
|
||||||
given("a registered synchronous one-way producer for endpoint direct:producer-test-1")
|
given("a registered synchronous one-way producer for endpoint direct:producer-test-1")
|
||||||
val producer = new TestProducer("direct:producer-test-1") with Sync with Oneway
|
val producer = newActor(() => new TestProducer("direct:producer-test-1") with Sync with Oneway)
|
||||||
producer.start
|
producer.start
|
||||||
|
|
||||||
when("a test message is sent to the producer")
|
when("a test message is sent to the producer")
|
||||||
|
|
@ -100,7 +100,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
|
||||||
|
|
||||||
scenario("produce message async oneway") {
|
scenario("produce message async oneway") {
|
||||||
given("a registered asynchronous one-way producer for endpoint direct:producer-test-1")
|
given("a registered asynchronous one-way producer for endpoint direct:producer-test-1")
|
||||||
val producer = new TestProducer("direct:producer-test-1") with Oneway
|
val producer = newActor(() => new TestProducer("direct:producer-test-1") with Oneway)
|
||||||
producer.start
|
producer.start
|
||||||
|
|
||||||
when("a test message is sent to the producer")
|
when("a test message is sent to the producer")
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.scalatest.{GivenWhenThen, BeforeAndAfterAll, FeatureSpec}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.{Actor, ActorRegistry}
|
import se.scalablesolutions.akka.actor.{Actor, ActorRegistry}
|
||||||
import se.scalablesolutions.akka.camel.{CamelContextManager, Message, Consumer}
|
import se.scalablesolutions.akka.camel.{CamelContextManager, Message, Consumer}
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with GivenWhenThen {
|
class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with GivenWhenThen {
|
||||||
var service: CamelService = CamelService.newInstance
|
var service: CamelService = CamelService.newInstance
|
||||||
|
|
@ -17,11 +18,11 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
|
||||||
CamelContextManager.init
|
CamelContextManager.init
|
||||||
CamelContextManager.context.addRoutes(new TestRoute)
|
CamelContextManager.context.addRoutes(new TestRoute)
|
||||||
// set expectations for testing purposes
|
// set expectations for testing purposes
|
||||||
service.consumerPublisher.expectPublishCount(1)
|
service.consumerPublisher.actor.asInstanceOf[ConsumerPublisher].expectPublishCount(1)
|
||||||
// start the CamelService
|
// start the CamelService
|
||||||
service.load
|
service.load
|
||||||
// await publication of first test consumer
|
// await publication of first test consumer
|
||||||
service.consumerPublisher.awaitPublish
|
service.consumerPublisher.actor.asInstanceOf[ConsumerPublisher].awaitPublish
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def afterAll = {
|
override protected def afterAll = {
|
||||||
|
|
@ -34,11 +35,11 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
|
||||||
scenario("access registered consumer actors via Camel direct-endpoints") {
|
scenario("access registered consumer actors via Camel direct-endpoints") {
|
||||||
|
|
||||||
given("two consumer actors registered before and after CamelService startup")
|
given("two consumer actors registered before and after CamelService startup")
|
||||||
service.consumerPublisher.expectPublishCount(1)
|
service.consumerPublisher.actor.asInstanceOf[ConsumerPublisher].expectPublishCount(1)
|
||||||
new TestConsumer("direct:publish-test-2").start
|
new TestConsumer("direct:publish-test-2").start
|
||||||
|
|
||||||
when("requests are sent to these actors")
|
when("requests are sent to these actors")
|
||||||
service.consumerPublisher.awaitPublish
|
service.consumerPublisher.actor.asInstanceOf[ConsumerPublisher].awaitPublish
|
||||||
val response1 = CamelContextManager.template.requestBody("direct:publish-test-1", "msg1")
|
val response1 = CamelContextManager.template.requestBody("direct:publish-test-1", "msg1")
|
||||||
val response2 = CamelContextManager.template.requestBody("direct:publish-test-2", "msg2")
|
val response2 = CamelContextManager.template.requestBody("direct:publish-test-2", "msg2")
|
||||||
|
|
||||||
|
|
@ -53,7 +54,7 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
|
||||||
scenario("access an actor from the custom Camel route") {
|
scenario("access an actor from the custom Camel route") {
|
||||||
|
|
||||||
given("a registered actor and a custom route to that actor")
|
given("a registered actor and a custom route to that actor")
|
||||||
val actor = new TestActor().start
|
val actor = newActor[TestActor].start
|
||||||
|
|
||||||
when("sending a a message to that route")
|
when("sending a a message to that route")
|
||||||
val response = CamelContextManager.template.requestBody("direct:custom-route-test-1", "msg3")
|
val response = CamelContextManager.template.requestBody("direct:custom-route-test-1", "msg3")
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,23 @@ import org.scalatest.junit.JUnitSuite
|
||||||
import se.scalablesolutions.akka.camel.Consumer
|
import se.scalablesolutions.akka.camel.Consumer
|
||||||
import se.scalablesolutions.akka.camel.support.{Receive, Countdown}
|
import se.scalablesolutions.akka.camel.support.{Receive, Countdown}
|
||||||
import se.scalablesolutions.akka.actor.{ActorRegistry, ActorRegistered, Actor}
|
import se.scalablesolutions.akka.actor.{ActorRegistry, ActorRegistered, Actor}
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class PublishRequestorTest extends JUnitSuite {
|
class PublishRequestorTest extends JUnitSuite {
|
||||||
@After def tearDown = ActorRegistry.shutdownAll
|
@After def tearDown = ActorRegistry.shutdownAll
|
||||||
|
|
||||||
@Test def shouldReceivePublishRequestOnActorRegisteredEvent = {
|
@Test def shouldReceivePublishRequestOnActorRegisteredEvent = {
|
||||||
val consumer = new Actor with Consumer {
|
val consumer = newActor(() => new Actor with Consumer {
|
||||||
def endpointUri = "mock:test"
|
def endpointUri = "mock:test"
|
||||||
protected def receive = null
|
protected def receive = null
|
||||||
}
|
})
|
||||||
val publisher = new PublisherMock with Countdown[Publish]
|
val publisher = newActor(() => new PublisherMock with Countdown[Publish])
|
||||||
val requestor = new PublishRequestor(publisher)
|
val requestor = newActor(() => new PublishRequestor(publisher))
|
||||||
publisher.start
|
publisher.start
|
||||||
requestor.start
|
requestor.start
|
||||||
requestor.!(ActorRegistered(consumer))(None)
|
requestor.!(ActorRegistered(consumer))(None)
|
||||||
publisher.waitFor
|
publisher.actor.asInstanceOf[Countdown[Publish]].waitFor
|
||||||
assert(publisher.received === Publish("mock:test", consumer.uuid, true))
|
assert(publisher.actor.asInstanceOf[PublisherMock].received === Publish("mock:test", consumer.uuid, true))
|
||||||
publisher.stop
|
publisher.stop
|
||||||
requestor.stop
|
requestor.stop
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,29 +4,30 @@ import org.junit.Test
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.Actor
|
||||||
|
import se.scalablesolutions.akka.actor.Actor._
|
||||||
import se.scalablesolutions.akka.actor.annotation.consume
|
import se.scalablesolutions.akka.actor.annotation.consume
|
||||||
import se.scalablesolutions.akka.camel.Consumer
|
import se.scalablesolutions.akka.camel.Consumer
|
||||||
|
|
||||||
class PublishTest extends JUnitSuite {
|
class PublishTest extends JUnitSuite {
|
||||||
@Test def shouldCreatePublishRequestList = {
|
@Test def shouldCreatePublishRequestList = {
|
||||||
val publish = Publish.forConsumers(List(new ConsumeAnnotatedActor))
|
val publish = Publish.forConsumers(List(newActor[ConsumeAnnotatedActor]))
|
||||||
assert(publish === List(Publish("mock:test1", "test", false)))
|
assert(publish === List(Publish("mock:test1", "test", false)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldCreateSomePublishRequestWithActorId = {
|
@Test def shouldCreateSomePublishRequestWithActorId = {
|
||||||
val publish = Publish.forConsumer(new ConsumeAnnotatedActor)
|
val publish = Publish.forConsumers(List(newActor[ConsumeAnnotatedActor]))
|
||||||
assert(publish === Some(Publish("mock:test1", "test", false)))
|
assert(publish === Some(Publish("mock:test1", "test", false)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldCreateSomePublishRequestWithActorUuid = {
|
@Test def shouldCreateSomePublishRequestWithActorUuid = {
|
||||||
val actor = new ConsumerActor
|
val ca = newActor[ConsumerActor]
|
||||||
val publish = Publish.forConsumer(actor)
|
val publish = Publish.forConsumers(List(ca))
|
||||||
assert(publish === Some(Publish("mock:test2", actor.uuid, true)))
|
assert(publish === Some(Publish("mock:test2", ca.uuid, true)))
|
||||||
assert(publish === Some(Publish("mock:test2", actor.uuid, true)))
|
assert(publish === Some(Publish("mock:test2", ca.uuid, true)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldCreateNone = {
|
@Test def shouldCreateNone = {
|
||||||
val publish = Publish.forConsumer(new PlainActor)
|
val publish = Publish.forConsumer(newActor[PlainActor])
|
||||||
assert(publish === None)
|
assert(publish === None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
|
|
||||||
*/
|
|
||||||
package se.scalablesolutions.akka.cluster.shoal
|
|
||||||
|
|
||||||
import java.util.Properties
|
|
||||||
|
|
||||||
import se.scalablesolutions.akka.config.Config.config
|
|
||||||
import se.scalablesolutions.akka.remote.{ClusterActor, BasicClusterActor, RemoteServer}
|
|
||||||
|
|
||||||
import com.sun.enterprise.ee.cms.core._
|
|
||||||
import com.sun.enterprise.ee.cms.impl.client._
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clustering support via Shoal.
|
|
||||||
*/
|
|
||||||
class ShoalClusterActor extends BasicClusterActor {
|
|
||||||
|
|
||||||
type ADDR_T = String
|
|
||||||
|
|
||||||
@volatile protected var gms : Option[GroupManagementService] = None
|
|
||||||
protected lazy val serverName : String = RemoteServer.HOSTNAME + ":" + RemoteServer.PORT
|
|
||||||
@volatile private var isActive = false
|
|
||||||
|
|
||||||
lazy val topic : String = config.getString("akka.remote.cluster.shoal.topic") getOrElse "akka-messages"
|
|
||||||
|
|
||||||
override def init = {
|
|
||||||
super.init
|
|
||||||
gms = Some(createGMS)
|
|
||||||
isActive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override def shutdown = {
|
|
||||||
super.shutdown
|
|
||||||
isActive = false
|
|
||||||
for(g <- gms) g.shutdown(GMSConstants.shutdownType.INSTANCE_SHUTDOWN)
|
|
||||||
gms = None
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Properties instance with properties designated for the underlying
|
|
||||||
* Shoal cluster transport (JXTA,JGroups)
|
|
||||||
*/
|
|
||||||
protected def properties() : Properties = {
|
|
||||||
config.getConfigMap("akka.remote.cluster.shoal.properties").map( m => {
|
|
||||||
new Properties(){
|
|
||||||
for(key <- m.keys) setProperty(key,m(key))
|
|
||||||
}
|
|
||||||
}).getOrElse(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a GroupManagementService, provides it with the proper properties
|
|
||||||
* Adds callbacks and boots up the cluster
|
|
||||||
*/
|
|
||||||
protected def createGMS : GroupManagementService = {
|
|
||||||
val g = GMSFactory
|
|
||||||
.startGMSModule(serverName,name, GroupManagementService.MemberType.CORE, properties())
|
|
||||||
.asInstanceOf[GroupManagementService]
|
|
||||||
val callback = createCallback
|
|
||||||
g.addActionFactory(new JoinNotificationActionFactoryImpl(callback))
|
|
||||||
g.addActionFactory(new FailureSuspectedActionFactoryImpl(callback))
|
|
||||||
g.addActionFactory(new FailureNotificationActionFactoryImpl(callback))
|
|
||||||
g.addActionFactory(new PlannedShutdownActionFactoryImpl(callback))
|
|
||||||
g.addActionFactory(new MessageActionFactoryImpl(callback), topic)
|
|
||||||
g.join
|
|
||||||
g
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a CallBack instance that deals with the cluster signalling
|
|
||||||
*/
|
|
||||||
protected def createCallback : CallBack = {
|
|
||||||
import scala.collection.JavaConversions._
|
|
||||||
import ClusterActor._
|
|
||||||
|
|
||||||
val me = this
|
|
||||||
new CallBack {
|
|
||||||
def processNotification(signal : Signal) {
|
|
||||||
try {
|
|
||||||
signal.acquire()
|
|
||||||
if(isActive) {
|
|
||||||
signal match {
|
|
||||||
case ms : MessageSignal => me ! Message[ADDR_T](ms.getMemberToken,ms.getMessage)
|
|
||||||
case jns : JoinNotificationSignal => me ! View[ADDR_T](Set[ADDR_T]() ++ jns.getCurrentCoreMembers - serverName)
|
|
||||||
case fss : FailureSuspectedSignal => me ! Zombie[ADDR_T](fss.getMemberToken)
|
|
||||||
case fns : FailureNotificationSignal => me ! Zombie[ADDR_T](fns.getMemberToken)
|
|
||||||
case _ => log.debug("Unhandled signal: [%s]",signal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signal.release()
|
|
||||||
} catch {
|
|
||||||
case e : SignalAcquireException => log.warning(e,"SignalAcquireException")
|
|
||||||
case e : SignalReleaseException => log.warning(e,"SignalReleaseException")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def toOneNode(dest : ADDR_T, msg : Array[Byte]) : Unit =
|
|
||||||
for(g <- gms) g.getGroupHandle.sendMessage(dest,topic, msg)
|
|
||||||
|
|
||||||
protected def toAllNodes(msg : Array[Byte]) : Unit =
|
|
||||||
for(g <- gms) g.getGroupHandle.sendMessage(topic, msg)
|
|
||||||
}
|
|
||||||
|
|
@ -5,15 +5,12 @@
|
||||||
package se.scalablesolutions.akka.comet
|
package se.scalablesolutions.akka.comet
|
||||||
|
|
||||||
import org.atmosphere.cpr.{AtmosphereResourceEvent, AtmosphereResource}
|
import org.atmosphere.cpr.{AtmosphereResourceEvent, AtmosphereResource}
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.Actor._
|
||||||
|
|
||||||
class AkkaBroadcaster extends org.atmosphere.jersey.JerseyBroadcaster {
|
class AkkaBroadcaster extends org.atmosphere.jersey.JerseyBroadcaster {
|
||||||
name = classOf[AkkaBroadcaster].getName
|
name = classOf[AkkaBroadcaster].getName
|
||||||
|
|
||||||
val caster = new Actor {
|
val caster = actor { case f : Function0[_] => f() }
|
||||||
def receive = { case f : Function0[_] => f() }
|
|
||||||
start
|
|
||||||
}
|
|
||||||
|
|
||||||
override def destroy {
|
override def destroy {
|
||||||
super.destroy
|
super.destroy
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,8 @@ object ActiveObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
||||||
def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long,
|
||||||
|
dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(false, restartCallbacks)
|
val actor = new Dispatcher(false, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(intf, target, actor, None, timeout)
|
newInstance(intf, target, actor, None, timeout)
|
||||||
|
|
@ -194,7 +195,8 @@ object ActiveObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
||||||
def newInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean,
|
||||||
|
dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(target, actor, None, timeout)
|
newInstance(target, actor, None, timeout)
|
||||||
|
|
@ -208,7 +210,8 @@ object ActiveObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
||||||
def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean,
|
||||||
|
dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(intf, target, actor, None, timeout)
|
newInstance(intf, target, actor, None, timeout)
|
||||||
|
|
@ -222,7 +225,8 @@ object ActiveObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
||||||
def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher,
|
||||||
|
hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(false, restartCallbacks)
|
val actor = new Dispatcher(false, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
||||||
|
|
@ -236,35 +240,40 @@ object ActiveObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
||||||
def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher,
|
||||||
|
hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(false, restartCallbacks)
|
val actor = new Dispatcher(false, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
||||||
def newRemoteInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher, hostname: String, port: Int): T = {
|
def newRemoteInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean,
|
||||||
|
dispatcher: MessageDispatcher, hostname: String, port: Int): T = {
|
||||||
val actor = new Dispatcher(transactionRequired, None)
|
val actor = new Dispatcher(transactionRequired, None)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
|
||||||
def newRemoteInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newRemoteInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher,
|
||||||
|
hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
||||||
def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher, hostname: String, port: Int): T = {
|
def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean,
|
||||||
|
dispatcher: MessageDispatcher, hostname: String, port: Int): T = {
|
||||||
val actor = new Dispatcher(transactionRequired, None)
|
val actor = new Dispatcher(transactionRequired, None)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
@deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
|
||||||
def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean,
|
||||||
|
dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = {
|
||||||
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
val actor = new Dispatcher(transactionRequired, restartCallbacks)
|
||||||
actor.messageDispatcher = dispatcher
|
actor.messageDispatcher = dispatcher
|
||||||
newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
|
||||||
|
|
@ -274,11 +283,10 @@ object ActiveObject {
|
||||||
val proxy = Proxy.newInstance(target, false, false)
|
val proxy = Proxy.newInstance(target, false, false)
|
||||||
actor.initialize(target, proxy)
|
actor.initialize(target, proxy)
|
||||||
actor.timeout = timeout
|
actor.timeout = timeout
|
||||||
if (remoteAddress.isDefined) {
|
if (remoteAddress.isDefined) actor.makeRemote(remoteAddress.get)
|
||||||
actor.makeRemote(remoteAddress.get)
|
val actorId = new ActorID(() => actor)
|
||||||
}
|
AspectInitRegistry.register(proxy, AspectInit(target, actorId, remoteAddress, timeout))
|
||||||
AspectInitRegistry.register(proxy, AspectInit(target, actor, remoteAddress, timeout))
|
actorId.start
|
||||||
actor.start
|
|
||||||
proxy.asInstanceOf[T]
|
proxy.asInstanceOf[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,20 +294,18 @@ object ActiveObject {
|
||||||
val proxy = Proxy.newInstance(Array(intf), Array(target), false, false)
|
val proxy = Proxy.newInstance(Array(intf), Array(target), false, false)
|
||||||
actor.initialize(target.getClass, target)
|
actor.initialize(target.getClass, target)
|
||||||
actor.timeout = timeout
|
actor.timeout = timeout
|
||||||
if (remoteAddress.isDefined) {
|
if (remoteAddress.isDefined) actor.makeRemote(remoteAddress.get)
|
||||||
actor.makeRemote(remoteAddress.get)
|
val actorId = new ActorID(() => actor)
|
||||||
}
|
AspectInitRegistry.register(proxy, AspectInit(intf, actorId, remoteAddress, timeout))
|
||||||
AspectInitRegistry.register(proxy, AspectInit(intf, actor, remoteAddress, timeout))
|
actorId.start
|
||||||
actor.start
|
|
||||||
proxy.asInstanceOf[T]
|
proxy.asInstanceOf[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the underlying dispatcher actor for the given active object.
|
* Get the underlying dispatcher actor for the given active object.
|
||||||
*/
|
*/
|
||||||
def actorFor(obj: AnyRef): Option[Actor] = {
|
def actorFor(obj: AnyRef): Option[ActorID] =
|
||||||
ActorRegistry.actorsFor(classOf[Dispatcher]).find(a=>a.target == Some(obj))
|
ActorRegistry.actorsFor(classOf[Dispatcher]).find(a => a.actor.asInstanceOf[Dispatcher].target == Some(obj))
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Links an other active object to this active object.
|
* Links an other active object to this active object.
|
||||||
|
|
@ -382,10 +388,10 @@ private[akka] object AspectInitRegistry {
|
||||||
|
|
||||||
private[akka] sealed case class AspectInit(
|
private[akka] sealed case class AspectInit(
|
||||||
val target: Class[_],
|
val target: Class[_],
|
||||||
val actor: Dispatcher,
|
val actorId: ActorID,
|
||||||
val remoteAddress: Option[InetSocketAddress],
|
val remoteAddress: Option[InetSocketAddress],
|
||||||
val timeout: Long) {
|
val timeout: Long) {
|
||||||
def this(target: Class[_],actor: Dispatcher, timeout: Long) = this(target, actor, None, timeout)
|
def this(target: Class[_], actorId: ActorID, timeout: Long) = this(target, actorId, None, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -399,7 +405,7 @@ private[akka] sealed case class AspectInit(
|
||||||
private[akka] sealed class ActiveObjectAspect {
|
private[akka] sealed class ActiveObjectAspect {
|
||||||
@volatile private var isInitialized = false
|
@volatile private var isInitialized = false
|
||||||
private var target: Class[_] = _
|
private var target: Class[_] = _
|
||||||
private var actor: Dispatcher = _
|
private var actorId: ActorID = _
|
||||||
private var remoteAddress: Option[InetSocketAddress] = _
|
private var remoteAddress: Option[InetSocketAddress] = _
|
||||||
private var timeout: Long = _
|
private var timeout: Long = _
|
||||||
|
|
||||||
|
|
@ -408,7 +414,7 @@ private[akka] sealed class ActiveObjectAspect {
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
val init = AspectInitRegistry.initFor(joinPoint.getThis)
|
val init = AspectInitRegistry.initFor(joinPoint.getThis)
|
||||||
target = init.target
|
target = init.target
|
||||||
actor = init.actor
|
actorId = init.actorId
|
||||||
remoteAddress = init.remoteAddress
|
remoteAddress = init.remoteAddress
|
||||||
timeout = init.timeout
|
timeout = init.timeout
|
||||||
isInitialized = true
|
isInitialized = true
|
||||||
|
|
@ -424,10 +430,10 @@ private[akka] sealed class ActiveObjectAspect {
|
||||||
private def localDispatch(joinPoint: JoinPoint): AnyRef = {
|
private def localDispatch(joinPoint: JoinPoint): AnyRef = {
|
||||||
val rtti = joinPoint.getRtti.asInstanceOf[MethodRtti]
|
val rtti = joinPoint.getRtti.asInstanceOf[MethodRtti]
|
||||||
if (isOneWay(rtti)) {
|
if (isOneWay(rtti)) {
|
||||||
(actor ! Invocation(joinPoint, true, true) ).asInstanceOf[AnyRef]
|
(actorId ! Invocation(joinPoint, true, true) ).asInstanceOf[AnyRef]
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val result = actor !! (Invocation(joinPoint, false, isVoid(rtti)), timeout)
|
val result = actorId !! (Invocation(joinPoint, false, isVoid(rtti)), timeout)
|
||||||
if (result.isDefined) result.get
|
if (result.isDefined) result.get
|
||||||
else throw new IllegalStateException("No result defined for invocation [" + joinPoint + "]")
|
else throw new IllegalStateException("No result defined for invocation [" + joinPoint + "]")
|
||||||
}
|
}
|
||||||
|
|
@ -441,13 +447,13 @@ private[akka] sealed class ActiveObjectAspect {
|
||||||
.setId(RemoteRequestIdFactory.nextId)
|
.setId(RemoteRequestIdFactory.nextId)
|
||||||
.setMethod(rtti.getMethod.getName)
|
.setMethod(rtti.getMethod.getName)
|
||||||
.setTarget(target.getName)
|
.setTarget(target.getName)
|
||||||
.setUuid(actor.uuid)
|
.setUuid(actorId.uuid)
|
||||||
.setTimeout(timeout)
|
.setTimeout(timeout)
|
||||||
.setIsActor(false)
|
.setIsActor(false)
|
||||||
.setIsOneWay(oneWay_?)
|
.setIsOneWay(oneWay_?)
|
||||||
.setIsEscaped(false)
|
.setIsEscaped(false)
|
||||||
RemoteProtocolBuilder.setMessage(message, requestBuilder)
|
RemoteProtocolBuilder.setMessage(message, requestBuilder)
|
||||||
val id = actor.registerSupervisorAsRemoteActor
|
val id = actorId.actor.registerSupervisorAsRemoteActor
|
||||||
if (id.isDefined) requestBuilder.setSupervisorUuid(id.get)
|
if (id.isDefined) requestBuilder.setSupervisorUuid(id.get)
|
||||||
val remoteMessage = requestBuilder.build
|
val remoteMessage = requestBuilder.build
|
||||||
val future = RemoteClient.clientFor(remoteAddress.get).send(remoteMessage, None)
|
val future = RemoteClient.clientFor(remoteAddress.get).send(remoteMessage, None)
|
||||||
|
|
@ -513,8 +519,8 @@ private[akka] sealed class ActiveObjectAspect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jan Kronquist: started work on issue 121
|
// FIXME Jan Kronquist: started work on issue 121
|
||||||
private[akka] case class Link(val actor: Actor)
|
private[akka] case class Link(val actor: ActorID)
|
||||||
|
|
||||||
object Dispatcher {
|
object Dispatcher {
|
||||||
val ZERO_ITEM_CLASS_ARRAY = Array[Class[_]]()
|
val ZERO_ITEM_CLASS_ARRAY = Array[Class[_]]()
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ abstract class RemoteActor(hostname: String, port: Int) extends Actor {
|
||||||
makeRemote(hostname, port)
|
makeRemote(hostname, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Life-cycle messages for the Actors
|
||||||
@serializable sealed trait LifeCycleMessage
|
@serializable sealed trait LifeCycleMessage
|
||||||
case class HotSwap(code: Option[PartialFunction[Any, Unit]]) extends LifeCycleMessage
|
case class HotSwap(code: Option[PartialFunction[Any, Unit]]) extends LifeCycleMessage
|
||||||
case class Restart(reason: Throwable) extends LifeCycleMessage
|
case class Restart(reason: Throwable) extends LifeCycleMessage
|
||||||
|
|
@ -55,30 +56,231 @@ case class Unlink(child: ActorID) extends LifeCycleMessage
|
||||||
case class UnlinkAndStop(child: ActorID) extends LifeCycleMessage
|
case class UnlinkAndStop(child: ActorID) extends LifeCycleMessage
|
||||||
case object Kill extends LifeCycleMessage
|
case object Kill extends LifeCycleMessage
|
||||||
|
|
||||||
|
// Exceptions for Actors
|
||||||
class ActorKilledException private[akka](message: String) extends RuntimeException(message)
|
class ActorKilledException private[akka](message: String) extends RuntimeException(message)
|
||||||
|
class ActorInitializationException private[akka](message: String) extends RuntimeException(message)
|
||||||
|
|
||||||
sealed abstract class DispatcherType
|
/**
|
||||||
object DispatcherType {
|
* Utility class with factory methods for creating Actors.
|
||||||
case object EventBasedThreadPooledProxyInvokingDispatcher extends DispatcherType
|
*
|
||||||
case object EventBasedSingleThreadDispatcher extends DispatcherType
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||||
case object EventBasedThreadPoolDispatcher extends DispatcherType
|
*/
|
||||||
case object ThreadBasedDispatcher extends DispatcherType
|
object Actor extends Logging {
|
||||||
|
val TIMEOUT = config.getInt("akka.actor.timeout", 5000)
|
||||||
|
val HOSTNAME = config.getString("akka.remote.server.hostname", "localhost")
|
||||||
|
val PORT = config.getInt("akka.remote.server.port", 9999)
|
||||||
|
val SERIALIZE_MESSAGES = config.getBool("akka.actor.serialize-messages", false)
|
||||||
|
|
||||||
|
// FIXME remove next release
|
||||||
|
object Sender {
|
||||||
|
@deprecated("import Actor.Sender.Self is not needed anymore, just use 'actor ! msg'")
|
||||||
|
object Self
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ActorID out of the Actor with type T.
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
* val actor = newActor[MyActor]
|
||||||
|
* actor.start
|
||||||
|
* actor ! message
|
||||||
|
* actor.stop
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
def newActor[T <: Actor: Manifest]: ActorID = new ActorID(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ActorID out of the Actor. Allows you to pass in a factory function
|
||||||
|
* that creates the Actor. Please note that this function can be invoked multiple
|
||||||
|
* times if for example the Actor is supervised and needs to be restarted.
|
||||||
|
* <p/>
|
||||||
|
* This function should <b>NOT</b> be used for remote actors.
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
* val actor = newActor(() => new MyActor)
|
||||||
|
* actor.start
|
||||||
|
* actor ! message
|
||||||
|
* actor.stop
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
def newActor(factory: () => Actor): ActorID = new ActorID(factory)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use to create an anonymous event-driven actor.
|
||||||
|
* <p/>
|
||||||
|
* The actor is created with a 'permanent' life-cycle configuration, which means that
|
||||||
|
* if the actor is supervised and dies it will be restarted.
|
||||||
|
* <p/>
|
||||||
|
* The actor is started when created.
|
||||||
|
* Example:
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
*
|
||||||
|
* val a = actor {
|
||||||
|
* case msg => ... // handle message
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
def actor(body: PartialFunction[Any, Unit]): ActorID =
|
||||||
|
new ActorID(() => new Actor() {
|
||||||
|
lifeCycle = Some(LifeCycle(Permanent))
|
||||||
|
start
|
||||||
|
def receive: PartialFunction[Any, Unit] = body
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use to create an anonymous transactional event-driven actor.
|
||||||
|
* <p/>
|
||||||
|
* The actor is created with a 'permanent' life-cycle configuration, which means that
|
||||||
|
* if the actor is supervised and dies it will be restarted.
|
||||||
|
* <p/>
|
||||||
|
* The actor is started when created.
|
||||||
|
* Example:
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
*
|
||||||
|
* val a = transactor {
|
||||||
|
* case msg => ... // handle message
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
def transactor(body: PartialFunction[Any, Unit]): ActorID =
|
||||||
|
new ActorID(() => new Transactor() {
|
||||||
|
lifeCycle = Some(LifeCycle(Permanent))
|
||||||
|
start
|
||||||
|
def receive: PartialFunction[Any, Unit] = body
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use to create an anonymous event-driven actor with a 'temporary' life-cycle configuration,
|
||||||
|
* which means that if the actor is supervised and dies it will *not* be restarted.
|
||||||
|
* <p/>
|
||||||
|
* The actor is started when created.
|
||||||
|
* Example:
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
*
|
||||||
|
* val a = temporaryActor {
|
||||||
|
* case msg => ... // handle message
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
def temporaryActor(body: PartialFunction[Any, Unit]): ActorID =
|
||||||
|
new ActorID(() => new Actor() {
|
||||||
|
lifeCycle = Some(LifeCycle(Temporary))
|
||||||
|
start
|
||||||
|
def receive = body
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use to create an anonymous event-driven actor with both an init block and a message loop block.
|
||||||
|
* <p/>
|
||||||
|
* The actor is created with a 'permanent' life-cycle configuration, which means that
|
||||||
|
* if the actor is supervised and dies it will be restarted.
|
||||||
|
* <p/>
|
||||||
|
* The actor is started when created.
|
||||||
|
* Example:
|
||||||
|
* <pre>
|
||||||
|
* val a = Actor.init {
|
||||||
|
* ... // init stuff
|
||||||
|
* } receive {
|
||||||
|
* case msg => ... // handle message
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
def init[A](body: => Unit) = {
|
||||||
|
def handler[A](body: => Unit) = new {
|
||||||
|
def receive(handler: PartialFunction[Any, Unit]) =
|
||||||
|
new ActorID(() => new Actor() {
|
||||||
|
lifeCycle = Some(LifeCycle(Permanent))
|
||||||
|
start
|
||||||
|
body
|
||||||
|
def receive = handler
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handler(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use to spawn out a block of code in an event-driven actor. Will shut actor down when
|
||||||
|
* the block has been executed.
|
||||||
|
* <p/>
|
||||||
|
* NOTE: If used from within an Actor then has to be qualified with 'Actor.spawn' since
|
||||||
|
* there is a method 'spawn[ActorType]' in the Actor trait already.
|
||||||
|
* Example:
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
*
|
||||||
|
* spawn {
|
||||||
|
* ... // do stuff
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
def spawn(body: => Unit): Unit = {
|
||||||
|
case object Spawn
|
||||||
|
new Actor() {
|
||||||
|
start
|
||||||
|
self ! Spawn
|
||||||
|
def receive = {
|
||||||
|
case Spawn => body; stop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* FIXME document
|
||||||
|
*
|
||||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||||
*/
|
*/
|
||||||
class ActorMessageInvoker(val actor: Actor) extends MessageInvoker {
|
class ActorMessageInvoker(val actorId: ActorID) extends MessageInvoker {
|
||||||
def invoke(handle: MessageInvocation) = actor.invoke(handle)
|
def invoke(handle: MessageInvocation) = actorId.actor.invoke(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ActorID private[akka] (private[akka] val actor: Actor) {
|
/**
|
||||||
if (actor eq null) throw new IllegalArgumentException("Actor instance passed to ActorID can not be 'null'")
|
* ActorID is an immutable and serializable handle to an Actor.
|
||||||
|
* Create an ActorID for an Actor by using the factory method on the Actor object.
|
||||||
|
* Here is an example:
|
||||||
|
* <pre>
|
||||||
|
* import Actor._
|
||||||
|
*
|
||||||
|
* val actor = newActor[MyActor]
|
||||||
|
* actor.start
|
||||||
|
* actor ! message
|
||||||
|
* actor.stop
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||||
|
*/
|
||||||
|
final class ActorID private[akka] () {
|
||||||
|
private[akka] var newActorFactory: Either[Option[Class[_ <: Actor]], Option[() => Actor]] = Left(None)
|
||||||
|
|
||||||
|
private[akka] def this(clazz: Class[_ <: Actor]) = {
|
||||||
|
this()
|
||||||
|
newActorFactory = Left(Some(clazz))
|
||||||
|
}
|
||||||
|
private[akka] def this(factory: () => Actor) = {
|
||||||
|
this()
|
||||||
|
newActorFactory = Right(Some(factory))
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val actor: Actor = {
|
||||||
|
val actor = newActorFactory match {
|
||||||
|
case Left(Some(clazz)) => clazz.newInstance
|
||||||
|
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 ActorID can not be 'null'")
|
||||||
|
actor
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Starts up the actor and its message queue.
|
* Starts up the actor and its message queue.
|
||||||
*/
|
*/
|
||||||
def start = actor.start
|
def start: ActorID = {
|
||||||
|
actor.start
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuts down the actor its dispatcher and message queue.
|
* Shuts down the actor its dispatcher and message queue.
|
||||||
|
|
@ -251,9 +453,19 @@ final class ActorID private[akka] (private[akka] val actor: Actor) {
|
||||||
*/
|
*/
|
||||||
def uuid = actor.uuid
|
def uuid = actor.uuid
|
||||||
|
|
||||||
override def toString = "ActorID[" + actor.toString + "]"
|
/**
|
||||||
override def hashCode = actor.hashCode
|
* Returns the remote address for the actor, if any, else None.
|
||||||
override def equals(that: AnyRef) = actor.equals(that)
|
*/
|
||||||
|
def remoteAddress: Option[InetSocketAddress] = actor._remoteAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default timeout for the actor.
|
||||||
|
*/
|
||||||
|
def timeout: Long = actor.timeout
|
||||||
|
|
||||||
|
override def toString: String = "ActorID[" + actor.toString + "]"
|
||||||
|
override def hashCode: Int = actor.hashCode
|
||||||
|
override def equals(that: Any): Boolean = actor.equals(that)
|
||||||
|
|
||||||
private[akka] def supervisor_=(sup: Option[ActorID]): Unit = actor._supervisor = sup
|
private[akka] def supervisor_=(sup: Option[ActorID]): Unit = actor._supervisor = sup
|
||||||
|
|
||||||
|
|
@ -267,151 +479,6 @@ final class ActorID private[akka] (private[akka] val actor: Actor) {
|
||||||
private[akka] def faultHandler_=(handler: Option[FaultHandlingStrategy]) = actor.faultHandler = handler
|
private[akka] def faultHandler_=(handler: Option[FaultHandlingStrategy]) = actor.faultHandler = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class with factory methods for creating Actors.
|
|
||||||
*
|
|
||||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
|
||||||
*/
|
|
||||||
object Actor extends Logging {
|
|
||||||
val TIMEOUT = config.getInt("akka.actor.timeout", 5000)
|
|
||||||
val SERIALIZE_MESSAGES = config.getBool("akka.actor.serialize-messages", false)
|
|
||||||
val HOSTNAME = config.getString("akka.remote.server.hostname", "localhost")
|
|
||||||
val PORT = config.getInt("akka.remote.server.port", 9999)
|
|
||||||
|
|
||||||
object Sender {
|
|
||||||
@deprecated("import Actor.Sender.Self is not needed anymore, just use 'actor ! msg'")
|
|
||||||
object Self
|
|
||||||
}
|
|
||||||
|
|
||||||
def newActor[T <: Actor: Manifest]: ActorID = {
|
|
||||||
val actor = manifest[T].erasure.asInstanceOf[Class[T]].newInstance
|
|
||||||
new ActorID(actor)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use to create an anonymous event-driven actor.
|
|
||||||
* <p/>
|
|
||||||
* The actor is created with a 'permanent' life-cycle configuration, which means that
|
|
||||||
* if the actor is supervised and dies it will be restarted.
|
|
||||||
* <p/>
|
|
||||||
* The actor is started when created.
|
|
||||||
* Example:
|
|
||||||
* <pre>
|
|
||||||
* import Actor._
|
|
||||||
*
|
|
||||||
* val a = actor {
|
|
||||||
* case msg => ... // handle message
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
def actor(body: PartialFunction[Any, Unit]): ActorID =
|
|
||||||
new ActorID(new Actor() {
|
|
||||||
lifeCycle = Some(LifeCycle(Permanent))
|
|
||||||
start
|
|
||||||
def receive: PartialFunction[Any, Unit] = body
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use to create an anonymous transactional event-driven actor.
|
|
||||||
* <p/>
|
|
||||||
* The actor is created with a 'permanent' life-cycle configuration, which means that
|
|
||||||
* if the actor is supervised and dies it will be restarted.
|
|
||||||
* <p/>
|
|
||||||
* The actor is started when created.
|
|
||||||
* Example:
|
|
||||||
* <pre>
|
|
||||||
* import Actor._
|
|
||||||
*
|
|
||||||
* val a = transactor {
|
|
||||||
* case msg => ... // handle message
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
def transactor(body: PartialFunction[Any, Unit]): ActorID =
|
|
||||||
new ActorID(new Transactor() {
|
|
||||||
lifeCycle = Some(LifeCycle(Permanent))
|
|
||||||
start
|
|
||||||
def receive: PartialFunction[Any, Unit] = body
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use to create an anonymous event-driven actor with a 'temporary' life-cycle configuration,
|
|
||||||
* which means that if the actor is supervised and dies it will *not* be restarted.
|
|
||||||
* <p/>
|
|
||||||
* The actor is started when created.
|
|
||||||
* Example:
|
|
||||||
* <pre>
|
|
||||||
* import Actor._
|
|
||||||
*
|
|
||||||
* val a = temporaryActor {
|
|
||||||
* case msg => ... // handle message
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
def temporaryActor(body: PartialFunction[Any, Unit]): ActorID =
|
|
||||||
new ActorID(new Actor() {
|
|
||||||
lifeCycle = Some(LifeCycle(Temporary))
|
|
||||||
start
|
|
||||||
def receive = body
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use to create an anonymous event-driven actor with both an init block and a message loop block.
|
|
||||||
* <p/>
|
|
||||||
* The actor is created with a 'permanent' life-cycle configuration, which means that
|
|
||||||
* if the actor is supervised and dies it will be restarted.
|
|
||||||
* <p/>
|
|
||||||
* The actor is started when created.
|
|
||||||
* Example:
|
|
||||||
* <pre>
|
|
||||||
* val a = Actor.init {
|
|
||||||
* ... // init stuff
|
|
||||||
* } receive {
|
|
||||||
* case msg => ... // handle message
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
def init[A](body: => Unit) = {
|
|
||||||
def handler[A](body: => Unit) = new {
|
|
||||||
def receive(handler: PartialFunction[Any, Unit]) =
|
|
||||||
new ActorID(new Actor() {
|
|
||||||
lifeCycle = Some(LifeCycle(Permanent))
|
|
||||||
start
|
|
||||||
body
|
|
||||||
def receive = handler
|
|
||||||
})
|
|
||||||
}
|
|
||||||
handler(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use to spawn out a block of code in an event-driven actor. Will shut actor down when
|
|
||||||
* the block has been executed.
|
|
||||||
* <p/>
|
|
||||||
* NOTE: If used from within an Actor then has to be qualified with 'Actor.spawn' since
|
|
||||||
* there is a method 'spawn[ActorType]' in the Actor trait already.
|
|
||||||
* Example:
|
|
||||||
* <pre>
|
|
||||||
* import Actor._
|
|
||||||
*
|
|
||||||
* spawn {
|
|
||||||
* ... // do stuff
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
def spawn(body: => Unit): Unit = {
|
|
||||||
case object Spawn
|
|
||||||
new Actor() {
|
|
||||||
start
|
|
||||||
selfId ! Spawn
|
|
||||||
def receive = {
|
|
||||||
case Spawn => body; stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model':
|
* Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model':
|
||||||
* <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a>
|
* <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a>
|
||||||
|
|
@ -429,7 +496,18 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
// Only mutable for RemoteServer in order to maintain identity across nodes
|
// Only mutable for RemoteServer in order to maintain identity across nodes
|
||||||
private[akka] var _uuid = UUID.newUuid.toString
|
private[akka] var _uuid = UUID.newUuid.toString
|
||||||
|
|
||||||
implicit private[akka] var _actorID: Option[ActorID] = None
|
/**
|
||||||
|
* The 'self' field holds the ActorID for this actor.
|
||||||
|
* Can be used to send messages to itself:
|
||||||
|
* <pre>
|
||||||
|
* self ! message
|
||||||
|
* </pre>
|
||||||
|
* Note: if you are using the 'self' field in the constructor of the Actor
|
||||||
|
* then you have to make the fields/operations that are using it 'lazy'.
|
||||||
|
*/
|
||||||
|
implicit val self = new ActorID(() => this)
|
||||||
|
|
||||||
|
protected implicit val selfOption = Some(self)
|
||||||
|
|
||||||
// ====================================
|
// ====================================
|
||||||
// private fields
|
// private fields
|
||||||
|
|
@ -619,26 +697,20 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
// ==== API ====
|
// ==== API ====
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
/**
|
|
||||||
* 'selfId' holds the ActorID for this actor.
|
|
||||||
*/
|
|
||||||
def selfId: ActorID =
|
|
||||||
_actorID.getOrElse(throw new IllegalStateException("ActorID for actor " + toString + " is not available"))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts up the actor and its message queue.
|
* Starts up the actor and its message queue.
|
||||||
*/
|
*/
|
||||||
def start: Unit = synchronized {
|
def start: Unit = synchronized {
|
||||||
if (_isShutDown) throw new IllegalStateException("Can't restart an actor that has been shut down with 'stop' or 'exit'")
|
if (_isShutDown) throw new IllegalStateException("Can't restart an actor that has been shut down with 'stop' or 'exit'")
|
||||||
if (!_isRunning) {
|
if (!_isRunning) {
|
||||||
messageDispatcher.register(selfId)
|
messageDispatcher.register(self)
|
||||||
messageDispatcher.start
|
messageDispatcher.start
|
||||||
_isRunning = true
|
_isRunning = true
|
||||||
init
|
init
|
||||||
initTransactionalState
|
initTransactionalState
|
||||||
}
|
}
|
||||||
Actor.log.debug("[%s] has started", toString)
|
Actor.log.debug("[%s] has started", toString)
|
||||||
ActorRegistry.register(selfId)
|
ActorRegistry.register(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -652,11 +724,11 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
*/
|
*/
|
||||||
def stop = synchronized {
|
def stop = synchronized {
|
||||||
if (_isRunning) {
|
if (_isRunning) {
|
||||||
messageDispatcher.unregister(selfId)
|
messageDispatcher.unregister(self)
|
||||||
_isRunning = false
|
_isRunning = false
|
||||||
_isShutDown = true
|
_isShutDown = true
|
||||||
shutdown
|
shutdown
|
||||||
ActorRegistry.unregister(selfId)
|
ActorRegistry.unregister(self)
|
||||||
_remoteAddress.foreach(address => RemoteClient.unregister(address.getHostName, address.getPort, uuid))
|
_remoteAddress.foreach(address => RemoteClient.unregister(address.getHostName, address.getPort, uuid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -688,14 +760,14 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
* Throws an IllegalStateException if unable to determine what to reply to
|
* Throws an IllegalStateException if unable to determine what to reply to
|
||||||
*/
|
*/
|
||||||
protected[this] def reply(message: Any) = if(!reply_?(message)) throw new IllegalStateException(
|
protected[this] def reply(message: Any) = if(!reply_?(message)) throw new IllegalStateException(
|
||||||
"\n\tNo sender in scope, can't reply. " +
|
"\n\tNo sender in scope, can't reply. " +
|
||||||
"\n\tYou have probably used the '!' method to either; " +
|
"\n\tYou have probably used the '!' method to either; " +
|
||||||
"\n\t\t1. Send a message to a remote actor which does not have a contact address." +
|
"\n\t\t1. Send a message to a remote actor which does not have a contact address." +
|
||||||
"\n\t\t2. Send a message from an instance that is *not* an actor" +
|
"\n\t\t2. Send a message from an instance that is *not* an actor" +
|
||||||
"\n\t\t3. Send a message to an Active Object annotated with the '@oneway' annotation? " +
|
"\n\t\t3. Send a message to an Active Object annotated with the '@oneway' annotation? " +
|
||||||
"\n\tIf so, switch to '!!' (or remove '@oneway') which passes on an implicit future" +
|
"\n\tIf so, switch to '!!' (or remove '@oneway') which passes on an implicit future" +
|
||||||
"\n\tthat will be bound by the argument passed to 'reply'." +
|
"\n\tthat will be bound by the argument passed to 'reply'." +
|
||||||
"\n\tAlternatively, you can use setReplyToAddress to make sure the actor can be contacted over the network.")
|
"\n\tAlternatively, you can use setReplyToAddress to make sure the actor can be contacted over the network.")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use <code>reply_?(..)</code> to reply with a message to the original sender of the message currently
|
* Use <code>reply_?(..)</code> to reply with a message to the original sender of the message currently
|
||||||
|
|
@ -725,9 +797,9 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
*/
|
*/
|
||||||
def dispatcher_=(md: MessageDispatcher): Unit = synchronized {
|
def dispatcher_=(md: MessageDispatcher): Unit = synchronized {
|
||||||
if (!_isRunning) {
|
if (!_isRunning) {
|
||||||
messageDispatcher.unregister(selfId)
|
messageDispatcher.unregister(self)
|
||||||
messageDispatcher = md
|
messageDispatcher = md
|
||||||
messageDispatcher.register(selfId)
|
messageDispatcher.register(self)
|
||||||
} else throw new IllegalArgumentException(
|
} else throw new IllegalArgumentException(
|
||||||
"Can not swap dispatcher for " + toString + " after it has been started")
|
"Can not swap dispatcher for " + toString + " after it has been started")
|
||||||
}
|
}
|
||||||
|
|
@ -786,7 +858,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
if (actorId.supervisor.isDefined) throw new IllegalStateException(
|
if (actorId.supervisor.isDefined) throw new IllegalStateException(
|
||||||
"Actor can only have one supervisor [" + actorId + "], e.g. link(actor) fails")
|
"Actor can only have one supervisor [" + actorId + "], e.g. link(actor) fails")
|
||||||
getLinkedActors.add(actorId)
|
getLinkedActors.add(actorId)
|
||||||
actorId.supervisor = Some(selfId)
|
actorId.supervisor = Some(self)
|
||||||
Actor.log.debug("Linking actor [%s] to actor [%s]", actorId, this)
|
Actor.log.debug("Linking actor [%s] to actor [%s]", actorId, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -907,7 +979,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
if (!dispatcher.isInstanceOf[ThreadBasedDispatcher]) {
|
if (!dispatcher.isInstanceOf[ThreadBasedDispatcher]) {
|
||||||
actor.dispatcher = dispatcher
|
actor.dispatcher = dispatcher
|
||||||
}
|
}
|
||||||
new ActorID(actor)
|
new ActorID(() => actor)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected[akka] def postMessageToMailbox(message: Any, sender: Option[ActorID]): Unit = {
|
protected[akka] def postMessageToMailbox(message: Any, sender: Option[ActorID]): Unit = {
|
||||||
|
|
@ -949,7 +1021,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
RemoteProtocolBuilder.setMessage(message, requestBuilder)
|
RemoteProtocolBuilder.setMessage(message, requestBuilder)
|
||||||
RemoteClient.clientFor(_remoteAddress.get).send[Any](requestBuilder.build, None)
|
RemoteClient.clientFor(_remoteAddress.get).send[Any](requestBuilder.build, None)
|
||||||
} else {
|
} else {
|
||||||
val invocation = new MessageInvocation(selfId, message, sender.map(Left(_)), transactionSet.get)
|
val invocation = new MessageInvocation(self, message, sender.map(Left(_)), transactionSet.get)
|
||||||
if (messageDispatcher.usesActorMailbox) {
|
if (messageDispatcher.usesActorMailbox) {
|
||||||
_mailbox.add(invocation)
|
_mailbox.add(invocation)
|
||||||
if (_isSuspended) invocation.send
|
if (_isSuspended) invocation.send
|
||||||
|
|
@ -982,7 +1054,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
} else {
|
} else {
|
||||||
val future = if (senderFuture.isDefined) senderFuture.get
|
val future = if (senderFuture.isDefined) senderFuture.get
|
||||||
else new DefaultCompletableFuture[T](timeout)
|
else new DefaultCompletableFuture[T](timeout)
|
||||||
val invocation = new MessageInvocation(selfId, message, Some(Right(future.asInstanceOf[CompletableFuture[Any]])), transactionSet.get)
|
val invocation = new MessageInvocation(self, message, Some(Right(future.asInstanceOf[CompletableFuture[Any]])), transactionSet.get)
|
||||||
|
|
||||||
if (messageDispatcher.usesActorMailbox)
|
if (messageDispatcher.usesActorMailbox)
|
||||||
_mailbox.add(invocation)
|
_mailbox.add(invocation)
|
||||||
|
|
@ -1027,9 +1099,9 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
_isKilled = true
|
_isKilled = true
|
||||||
Actor.log.error(e, "Could not invoke actor [%s]", this)
|
Actor.log.error(e, "Could not invoke actor [%s]", this)
|
||||||
// FIXME to fix supervisor restart of remote actor for oneway calls, inject a supervisor proxy that can send notification back to client
|
// FIXME to fix supervisor restart of remote actor for oneway calls, inject a supervisor proxy that can send notification back to client
|
||||||
if (_supervisor.isDefined) _supervisor.get ! Exit(selfId, e)
|
if (_supervisor.isDefined) _supervisor.get ! Exit(self, e)
|
||||||
replyTo match {
|
replyTo match {
|
||||||
case Some(Right(future)) => future.completeWithException(selfId, e)
|
case Some(Right(future)) => future.completeWithException(self, e)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -1078,7 +1150,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
Actor.log.error(e, "Exception when invoking \n\tactor [%s] \n\twith message [%s]", this, message)
|
Actor.log.error(e, "Exception when invoking \n\tactor [%s] \n\twith message [%s]", this, message)
|
||||||
|
|
||||||
replyTo match {
|
replyTo match {
|
||||||
case Some(Right(future)) => future.completeWithException(selfId, e)
|
case Some(Right(future)) => future.completeWithException(self, e)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1086,7 +1158,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
if (topLevelTransaction) clearTransactionSet
|
if (topLevelTransaction) clearTransactionSet
|
||||||
|
|
||||||
// FIXME to fix supervisor restart of remote actor for oneway calls, inject a supervisor proxy that can send notification back to client
|
// FIXME to fix supervisor restart of remote actor for oneway calls, inject a supervisor proxy that can send notification back to client
|
||||||
if (_supervisor.isDefined) _supervisor.get ! Exit(selfId, e)
|
if (_supervisor.isDefined) _supervisor.get ! Exit(self, e)
|
||||||
} finally {
|
} finally {
|
||||||
clearTransaction
|
clearTransaction
|
||||||
if (topLevelTransaction) clearTransactionSet
|
if (topLevelTransaction) clearTransactionSet
|
||||||
|
|
@ -1137,7 +1209,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
Actor.log.info("All linked actors have died permanently (they were all configured as TEMPORARY)" +
|
Actor.log.info("All linked actors have died permanently (they were all configured as TEMPORARY)" +
|
||||||
"\n\tshutting down and unlinking supervisor actor as well [%s].",
|
"\n\tshutting down and unlinking supervisor actor as well [%s].",
|
||||||
actor.id)
|
actor.id)
|
||||||
_supervisor.foreach(_ ! UnlinkAndStop(selfId))
|
_supervisor.foreach(_ ! UnlinkAndStop(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1155,7 +1227,7 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
|
|
||||||
private[akka] def registerSupervisorAsRemoteActor: Option[String] = synchronized {
|
private[akka] def registerSupervisorAsRemoteActor: Option[String] = synchronized {
|
||||||
if (_supervisor.isDefined) {
|
if (_supervisor.isDefined) {
|
||||||
RemoteClient.clientFor(_remoteAddress.get).registerSupervisorForActor(this)
|
RemoteClient.clientFor(_remoteAddress.get).registerSupervisorForActor(self)
|
||||||
Some(_supervisor.get.uuid)
|
Some(_supervisor.get.uuid)
|
||||||
} else None
|
} else None
|
||||||
}
|
}
|
||||||
|
|
@ -1203,3 +1275,11 @@ trait Actor extends TransactionManagement with Logging {
|
||||||
|
|
||||||
override def toString = "Actor[" + id + ":" + uuid + "]"
|
override def toString = "Actor[" + id + ":" + uuid + "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed abstract class DispatcherType
|
||||||
|
object DispatcherType {
|
||||||
|
case object EventBasedThreadPooledProxyInvokingDispatcher extends DispatcherType
|
||||||
|
case object EventBasedSingleThreadDispatcher extends DispatcherType
|
||||||
|
case object EventBasedThreadPoolDispatcher extends DispatcherType
|
||||||
|
case object ThreadBasedDispatcher extends DispatcherType
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,13 @@ object ActorRegistry extends Logging {
|
||||||
/**
|
/**
|
||||||
* Finds all actors that are subtypes of the class passed in as the Manifest argument.
|
* Finds all actors that are subtypes of the class passed in as the Manifest argument.
|
||||||
*/
|
*/
|
||||||
def actorsFor[T <: Actor](implicit manifest: Manifest[T]): List[T] = {
|
def actorsFor[T <: Actor](implicit manifest: Manifest[T]): List[ActorID] = {
|
||||||
val all = new ListBuffer[T]
|
val all = new ListBuffer[ActorID]
|
||||||
val elements = actorsByUUID.elements
|
val elements = actorsByUUID.elements
|
||||||
while (elements.hasMoreElements) {
|
while (elements.hasMoreElements) {
|
||||||
val actorId = elements.nextElement
|
val actorId = elements.nextElement
|
||||||
if (manifest.erasure.isAssignableFrom(actorId.actor.getClass)) {
|
if (manifest.erasure.isAssignableFrom(actorId.actor.getClass)) {
|
||||||
all += actorId.actor.asInstanceOf[T]
|
all += actorId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
all.toList
|
all.toList
|
||||||
|
|
@ -68,17 +68,16 @@ object ActorRegistry extends Logging {
|
||||||
/**
|
/**
|
||||||
* Finds all actors of the exact type specified by the class passed in as the Class argument.
|
* Finds all actors of the exact type specified by the class passed in as the Class argument.
|
||||||
*/
|
*/
|
||||||
def actorsFor[T <: Actor](clazz: Class[T]): List[T] = {
|
def actorsFor[T <: Actor](clazz: Class[T]): List[ActorID] = {
|
||||||
if (actorsByClassName.containsKey(clazz.getName)) {
|
if (actorsByClassName.containsKey(clazz.getName)) actorsByClassName.get(clazz.getName)
|
||||||
actorsByClassName.get(clazz.getName).asInstanceOf[List[T]]
|
else Nil
|
||||||
} else Nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all actors that has a specific id.
|
* Finds all actors that has a specific id.
|
||||||
*/
|
*/
|
||||||
def actorsFor(id: String): List[ActorID] = {
|
def actorsFor(id: String): List[ActorID] = {
|
||||||
if (actorsById.containsKey(id)) actorsById.get(id).asInstanceOf[List[ActorID]]
|
if (actorsById.containsKey(id)) actorsById.get(id)
|
||||||
else Nil
|
else Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ sealed class Agent[T] private (initialValue: T) extends Transactor {
|
||||||
|
|
||||||
private lazy val value = Ref[T]()
|
private lazy val value = Ref[T]()
|
||||||
|
|
||||||
this ! Value(initialValue)
|
self ! Value(initialValue)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Periodically handles incoming messages.
|
* Periodically handles incoming messages.
|
||||||
|
|
@ -157,22 +157,22 @@ sealed class Agent[T] private (initialValue: T) extends Transactor {
|
||||||
/**
|
/**
|
||||||
* Submits the provided function for execution against the internal agent's state.
|
* Submits the provided function for execution against the internal agent's state.
|
||||||
*/
|
*/
|
||||||
final def apply(message: (T => T)): Unit = this ! Function(message)
|
final def apply(message: (T => T)): Unit = self ! Function(message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits a new value to be set as the new agent's internal state.
|
* Submits a new value to be set as the new agent's internal state.
|
||||||
*/
|
*/
|
||||||
final def apply(message: T): Unit = this ! Value(message)
|
final def apply(message: T): Unit = self ! Value(message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits the provided function of type 'T => T' for execution against the internal agent's state.
|
* Submits the provided function of type 'T => T' for execution against the internal agent's state.
|
||||||
*/
|
*/
|
||||||
final def send(message: (T) => T): Unit = this ! Function(message)
|
final def send(message: (T) => T): Unit = self ! Function(message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits a new value to be set as the new agent's internal state.
|
* Submits a new value to be set as the new agent's internal state.
|
||||||
*/
|
*/
|
||||||
final def send(message: T): Unit = this ! Value(message)
|
final def send(message: T): Unit = self ! Value(message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously submits a procedure of type 'T => Unit' to read the internal state.
|
* Asynchronously submits a procedure of type 'T => Unit' to read the internal state.
|
||||||
|
|
@ -180,7 +180,7 @@ sealed class Agent[T] private (initialValue: T) extends Transactor {
|
||||||
* of the internal state will be used, depending on the underlying effective copyStrategy.
|
* of the internal state will be used, depending on the underlying effective copyStrategy.
|
||||||
* Does not change the value of the agent (this).
|
* Does not change the value of the agent (this).
|
||||||
*/
|
*/
|
||||||
final def sendProc(f: (T) => Unit): Unit = this ! Procedure(f)
|
final def sendProc(f: (T) => Unit): Unit = self ! Procedure(f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies function with type 'T => B' to the agent's internal state and then returns a new agent with the result.
|
* Applies function with type 'T => B' to the agent's internal state and then returns a new agent with the result.
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@ case class SchedulerException(msg: String, e: Throwable) extends RuntimeExceptio
|
||||||
* Rework of David Pollak's ActorPing class in the Lift Project
|
* Rework of David Pollak's ActorPing class in the Lift Project
|
||||||
* which is licensed under the Apache 2 License.
|
* which is licensed under the Apache 2 License.
|
||||||
*/
|
*/
|
||||||
class ScheduleActor(val receiver: Actor, val future: ScheduledFuture[AnyRef]) extends Actor with Logging {
|
class ScheduleActor(val receiver: ActorID, val future: ScheduledFuture[AnyRef]) extends Actor with Logging {
|
||||||
lifeCycle = Some(LifeCycle(Permanent))
|
lifeCycle = Some(LifeCycle(Permanent))
|
||||||
|
|
||||||
def receive = {
|
def receive = {
|
||||||
case UnSchedule =>
|
case UnSchedule =>
|
||||||
Scheduler.stopSupervising(this)
|
Scheduler.stopSupervising(self)
|
||||||
future.cancel(true)
|
future.cancel(true)
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
@ -39,18 +39,18 @@ class ScheduleActor(val receiver: Actor, val future: ScheduledFuture[AnyRef]) ex
|
||||||
|
|
||||||
object Scheduler extends Actor {
|
object Scheduler extends Actor {
|
||||||
private var service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
|
private var service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
|
||||||
private val schedulers = new ConcurrentHashMap[Actor, Actor]
|
private val schedulers = new ConcurrentHashMap[ActorID, ActorID]
|
||||||
faultHandler = Some(OneForOneStrategy(5, 5000))
|
faultHandler = Some(OneForOneStrategy(5, 5000))
|
||||||
trapExit = List(classOf[Throwable])
|
trapExit = List(classOf[Throwable])
|
||||||
start
|
start
|
||||||
|
|
||||||
def schedule(receiver: Actor, message: AnyRef, initialDelay: Long, delay: Long, timeUnit: TimeUnit) = {
|
def schedule(receiver: ActorID, message: AnyRef, initialDelay: Long, delay: Long, timeUnit: TimeUnit) = {
|
||||||
try {
|
try {
|
||||||
startLink(new ScheduleActor(
|
startLink(new ActorID(() => new ScheduleActor(
|
||||||
receiver,
|
receiver,
|
||||||
service.scheduleAtFixedRate(new java.lang.Runnable {
|
service.scheduleAtFixedRate(new java.lang.Runnable {
|
||||||
def run = receiver ! message;
|
def run = receiver ! message;
|
||||||
}, initialDelay, delay, timeUnit).asInstanceOf[ScheduledFuture[AnyRef]]))
|
}, initialDelay, delay, timeUnit).asInstanceOf[ScheduledFuture[AnyRef]])))
|
||||||
} catch {
|
} catch {
|
||||||
case e => throw SchedulerException(message + " could not be scheduled on " + receiver, e)
|
case e => throw SchedulerException(message + " could not be scheduled on " + receiver, e)
|
||||||
}
|
}
|
||||||
|
|
@ -58,9 +58,9 @@ object Scheduler extends Actor {
|
||||||
|
|
||||||
def restart = service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
|
def restart = service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
|
||||||
|
|
||||||
def stopSupervising(actor: Actor) = {
|
def stopSupervising(actorId: ActorID) = {
|
||||||
unlink(actor)
|
unlink(actorId)
|
||||||
schedulers.remove(actor)
|
schedulers.remove(actorId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def shutdown = {
|
override def shutdown = {
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@ sealed class Supervisor private[akka] (handler: FaultHandlingStrategy, trapExcep
|
||||||
|
|
||||||
trapExit = trapExceptions
|
trapExit = trapExceptions
|
||||||
faultHandler = Some(handler)
|
faultHandler = Some(handler)
|
||||||
|
|
||||||
|
// FIXME should Supervisor really havea newThreadBasedDispatcher??
|
||||||
dispatcher = Dispatchers.newThreadBasedDispatcher(this)
|
dispatcher = Dispatchers.newThreadBasedDispatcher(this)
|
||||||
|
|
||||||
private val actors = new ConcurrentHashMap[String, List[ActorID]]
|
private val actors = new ConcurrentHashMap[String, List[ActorID]]
|
||||||
|
|
@ -144,8 +146,8 @@ sealed class Supervisor private[akka] (handler: FaultHandlingStrategy, trapExcep
|
||||||
if (list eq null) List[ActorID]()
|
if (list eq null) List[ActorID]()
|
||||||
else list
|
else list
|
||||||
}
|
}
|
||||||
actors.put(className, supervisor.selfId :: currentSupervisors)
|
actors.put(className, supervisor.self :: currentSupervisors)
|
||||||
link(supervisor.selfId)
|
link(supervisor.self)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ package se.scalablesolutions.akka.config
|
||||||
import com.google.inject._
|
import com.google.inject._
|
||||||
|
|
||||||
import se.scalablesolutions.akka.config.ScalaConfig._
|
import se.scalablesolutions.akka.config.ScalaConfig._
|
||||||
import se.scalablesolutions.akka.actor.{Supervisor, ActiveObject, Dispatcher}
|
import se.scalablesolutions.akka.actor.{Supervisor, ActiveObject, Dispatcher, ActorID}
|
||||||
import se.scalablesolutions.akka.remote.RemoteServer
|
import se.scalablesolutions.akka.remote.RemoteServer
|
||||||
import se.scalablesolutions.akka.util.Logging
|
import se.scalablesolutions.akka.util.Logging
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
|
||||||
.actorsFor(RemoteServer.Address(component.remoteAddress.get.hostname, component.remoteAddress.get.port))
|
.actorsFor(RemoteServer.Address(component.remoteAddress.get.hostname, component.remoteAddress.get.port))
|
||||||
.activeObjects.put(targetClass.getName, proxy)
|
.activeObjects.put(targetClass.getName, proxy)
|
||||||
}
|
}
|
||||||
supervised ::= Supervise(actor, component.lifeCycle)
|
supervised ::= Supervise(new ActorID(() => actor), component.lifeCycle)
|
||||||
activeObjectRegistry.put(targetClass, (proxy, proxy, component))
|
activeObjectRegistry.put(targetClass, (proxy, proxy, component))
|
||||||
new DependencyBinding(targetClass, proxy)
|
new DependencyBinding(targetClass, proxy)
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +116,7 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
|
||||||
.actorsFor(RemoteServer.Address(component.remoteAddress.get.hostname, component.remoteAddress.get.port))
|
.actorsFor(RemoteServer.Address(component.remoteAddress.get.hostname, component.remoteAddress.get.port))
|
||||||
.activeObjects.put(targetClass.getName, proxy)
|
.activeObjects.put(targetClass.getName, proxy)
|
||||||
}
|
}
|
||||||
supervised ::= Supervise(actor, component.lifeCycle)
|
supervised ::= Supervise(new ActorID(() => actor), component.lifeCycle)
|
||||||
activeObjectRegistry.put(targetClass, (proxy, targetInstance, component))
|
activeObjectRegistry.put(targetClass, (proxy, targetInstance, component))
|
||||||
new DependencyBinding(targetClass, proxy)
|
new DependencyBinding(targetClass, proxy)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package se.scalablesolutions.akka.dispatch
|
package se.scalablesolutions.akka.dispatch
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.{Actor, ActorID}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scala API. Dispatcher factory.
|
* Scala API. Dispatcher factory.
|
||||||
|
|
@ -40,7 +40,7 @@ import se.scalablesolutions.akka.actor.Actor
|
||||||
*/
|
*/
|
||||||
object Dispatchers {
|
object Dispatchers {
|
||||||
object globalExecutorBasedEventDrivenDispatcher extends ExecutorBasedEventDrivenDispatcher("global") {
|
object globalExecutorBasedEventDrivenDispatcher extends ExecutorBasedEventDrivenDispatcher("global") {
|
||||||
override def register(actor: Actor) = {
|
override def register(actor: ActorID) = {
|
||||||
if (isShutdown) init
|
if (isShutdown) init
|
||||||
super.register(actor)
|
super.register(actor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
|
||||||
private def donateMessage(receiver: ActorID, thief: ActorID): Option[MessageInvocation] = {
|
private def donateMessage(receiver: ActorID, thief: ActorID): Option[MessageInvocation] = {
|
||||||
val donated = receiver._mailbox.pollLast
|
val donated = receiver._mailbox.pollLast
|
||||||
if (donated != null) {
|
if (donated != null) {
|
||||||
thief.selfId ! donated.message
|
thief.self ! donated.message
|
||||||
return Some(donated)
|
return Some(donated)
|
||||||
} else return None
|
} else return None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ package se.scalablesolutions.akka.dispatch
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
import java.util.Queue
|
import java.util.Queue
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.{Actor, ActorMessageInvoker}
|
import se.scalablesolutions.akka.actor.{Actor, ActorID, ActorMessageInvoker}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dedicates a unique thread for each actor passed in as reference. Served through its messageQueue.
|
* Dedicates a unique thread for each actor passed in as reference. Served through its messageQueue.
|
||||||
|
|
@ -17,7 +17,7 @@ import se.scalablesolutions.akka.actor.{Actor, ActorMessageInvoker}
|
||||||
class ThreadBasedDispatcher private[akka] (val name: String, val messageHandler: MessageInvoker)
|
class ThreadBasedDispatcher private[akka] (val name: String, val messageHandler: MessageInvoker)
|
||||||
extends MessageDispatcher {
|
extends MessageDispatcher {
|
||||||
|
|
||||||
def this(actor: Actor) = this(actor.getClass.getName, new ActorMessageInvoker(actor))
|
def this(actor: Actor) = this(actor.getClass.getName, new ActorMessageInvoker(new ActorID(() => actor)))
|
||||||
|
|
||||||
private val queue = new BlockingMessageQueue(name)
|
private val queue = new BlockingMessageQueue(name)
|
||||||
private var selectorThread: Thread = _
|
private var selectorThread: Thread = _
|
||||||
|
|
|
||||||
|
|
@ -212,19 +212,19 @@ abstract class BasicClusterActor extends ClusterActor with Logging {
|
||||||
* Registers a local endpoint
|
* Registers a local endpoint
|
||||||
*/
|
*/
|
||||||
def registerLocalNode(hostname: String, port: Int): Unit =
|
def registerLocalNode(hostname: String, port: Int): Unit =
|
||||||
selfId ! RegisterLocalNode(RemoteAddress(hostname, port))
|
self ! RegisterLocalNode(RemoteAddress(hostname, port))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deregisters a local endpoint
|
* Deregisters a local endpoint
|
||||||
*/
|
*/
|
||||||
def deregisterLocalNode(hostname: String, port: Int): Unit =
|
def deregisterLocalNode(hostname: String, port: Int): Unit =
|
||||||
selfId ! DeregisterLocalNode(RemoteAddress(hostname, port))
|
self ! DeregisterLocalNode(RemoteAddress(hostname, port))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcasts the specified message to all Actors of type Class on all known Nodes
|
* Broadcasts the specified message to all Actors of type Class on all known Nodes
|
||||||
*/
|
*/
|
||||||
def relayMessage(to: Class[_ <: Actor], msg: AnyRef): Unit =
|
def relayMessage(to: Class[_ <: Actor], msg: AnyRef): Unit =
|
||||||
selfId ! RelayedMessage(to.getName, msg)
|
self ! RelayedMessage(to.getName, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -261,7 +261,7 @@ object Cluster extends Cluster with Logging {
|
||||||
val sup = SupervisorFactory(
|
val sup = SupervisorFactory(
|
||||||
SupervisorConfig(
|
SupervisorConfig(
|
||||||
RestartStrategy(OneForOne, 5, 1000, List(classOf[Exception])),
|
RestartStrategy(OneForOne, 5, 1000, List(classOf[Exception])),
|
||||||
Supervise(actor.selfId, LifeCycle(Permanent)) :: Nil)
|
Supervise(actor.self, LifeCycle(Permanent)) :: Nil)
|
||||||
).newInstance
|
).newInstance
|
||||||
Some(sup)
|
Some(sup)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
package se.scalablesolutions.akka.remote
|
package se.scalablesolutions.akka.remote
|
||||||
|
|
||||||
import se.scalablesolutions.akka.remote.protobuf.RemoteProtocol.{RemoteRequest, RemoteReply}
|
import se.scalablesolutions.akka.remote.protobuf.RemoteProtocol.{RemoteRequest, RemoteReply}
|
||||||
import se.scalablesolutions.akka.actor.{Exit, Actor}
|
import se.scalablesolutions.akka.actor.{Exit, Actor, ActorID}
|
||||||
import se.scalablesolutions.akka.dispatch.{DefaultCompletableFuture, CompletableFuture}
|
import se.scalablesolutions.akka.dispatch.{DefaultCompletableFuture, CompletableFuture}
|
||||||
import se.scalablesolutions.akka.util.{UUID, Logging}
|
import se.scalablesolutions.akka.util.{UUID, Logging}
|
||||||
import se.scalablesolutions.akka.config.Config.config
|
import se.scalablesolutions.akka.config.Config.config
|
||||||
|
|
@ -53,21 +53,21 @@ object RemoteClient extends Logging {
|
||||||
|
|
||||||
// FIXME: simplify overloaded methods when we have Scala 2.8
|
// FIXME: simplify overloaded methods when we have Scala 2.8
|
||||||
|
|
||||||
def actorFor(className: String, hostname: String, port: Int): Actor =
|
def actorFor(className: String, hostname: String, port: Int): ActorID =
|
||||||
actorFor(className, className, 5000L, hostname, port)
|
actorFor(className, className, 5000L, hostname, port)
|
||||||
|
|
||||||
def actorFor(actorId: String, className: String, hostname: String, port: Int): Actor =
|
def actorFor(actorId: String, className: String, hostname: String, port: Int): ActorID =
|
||||||
actorFor(actorId, className, 5000L, hostname, port)
|
actorFor(actorId, className, 5000L, hostname, port)
|
||||||
|
|
||||||
def actorFor(className: String, timeout: Long, hostname: String, port: Int): Actor =
|
def actorFor(className: String, timeout: Long, hostname: String, port: Int): ActorID =
|
||||||
actorFor(className, className, timeout, hostname, port)
|
actorFor(className, className, timeout, hostname, port)
|
||||||
|
|
||||||
def actorFor(actorId: String, className: String, timeout: Long, hostname: String, port: Int): Actor = {
|
def actorFor(actorId: String, className: String, timeout: Long, hostname: String, port: Int): ActorID = new ActorID(() =>
|
||||||
new Actor {
|
new Actor {
|
||||||
start
|
start
|
||||||
val remoteClient = RemoteClient.clientFor(hostname, port)
|
val remoteClient = RemoteClient.clientFor(hostname, port)
|
||||||
|
|
||||||
override def postMessageToMailbox(message: Any, sender: Option[Actor]): Unit = {
|
override def postMessageToMailbox(message: Any, sender: Option[ActorID]): Unit = {
|
||||||
val requestBuilder = RemoteRequest.newBuilder
|
val requestBuilder = RemoteRequest.newBuilder
|
||||||
.setId(RemoteRequestIdFactory.nextId)
|
.setId(RemoteRequestIdFactory.nextId)
|
||||||
.setTarget(className)
|
.setTarget(className)
|
||||||
|
|
@ -77,10 +77,10 @@ object RemoteClient extends Logging {
|
||||||
.setIsOneWay(true)
|
.setIsOneWay(true)
|
||||||
.setIsEscaped(false)
|
.setIsEscaped(false)
|
||||||
if (sender.isDefined) {
|
if (sender.isDefined) {
|
||||||
val s = sender.get
|
val sndr = sender.get.actor
|
||||||
requestBuilder.setSourceTarget(s.getClass.getName)
|
requestBuilder.setSourceTarget(sndr.getClass.getName)
|
||||||
requestBuilder.setSourceUuid(s.uuid)
|
requestBuilder.setSourceUuid(sndr.uuid)
|
||||||
val (host, port) = s._replyToAddress.map(a => (a.getHostName, a.getPort)).getOrElse((Actor.HOSTNAME, Actor.PORT))
|
val (host, port) = sndr._replyToAddress.map(a => (a.getHostName, a.getPort)).getOrElse((Actor.HOSTNAME, Actor.PORT))
|
||||||
requestBuilder.setSourceHostname(host)
|
requestBuilder.setSourceHostname(host)
|
||||||
requestBuilder.setSourcePort(port)
|
requestBuilder.setSourcePort(port)
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +108,7 @@ object RemoteClient extends Logging {
|
||||||
|
|
||||||
def receive = {case _ => {}}
|
def receive = {case _ => {}}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
def clientFor(hostname: String, port: Int): RemoteClient = clientFor(new InetSocketAddress(hostname, port))
|
def clientFor(hostname: String, port: Int): RemoteClient = clientFor(new InetSocketAddress(hostname, port))
|
||||||
|
|
||||||
|
|
@ -174,8 +174,8 @@ class RemoteClient(val hostname: String, val port: Int) extends Logging {
|
||||||
|
|
||||||
@volatile private[remote] var isRunning = false
|
@volatile private[remote] var isRunning = false
|
||||||
private val futures = new ConcurrentHashMap[Long, CompletableFuture[_]]
|
private val futures = new ConcurrentHashMap[Long, CompletableFuture[_]]
|
||||||
private val supervisors = new ConcurrentHashMap[String, Actor]
|
private val supervisors = new ConcurrentHashMap[String, ActorID]
|
||||||
private[remote] val listeners = new ConcurrentSkipListSet[Actor]
|
private[remote] val listeners = new ConcurrentSkipListSet[ActorID]
|
||||||
|
|
||||||
private val channelFactory = new NioClientSocketChannelFactory(
|
private val channelFactory = new NioClientSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool,
|
Executors.newCachedThreadPool,
|
||||||
|
|
@ -200,7 +200,7 @@ class RemoteClient(val hostname: String, val port: Int) extends Logging {
|
||||||
val channel = connection.awaitUninterruptibly.getChannel
|
val channel = connection.awaitUninterruptibly.getChannel
|
||||||
openChannels.add(channel)
|
openChannels.add(channel)
|
||||||
if (!connection.isSuccess) {
|
if (!connection.isSuccess) {
|
||||||
listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientError(connection.getCause))
|
listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientError(connection.getCause))
|
||||||
log.error(connection.getCause, "Remote client connection to [%s:%s] has failed", hostname, port)
|
log.error(connection.getCause, "Remote client connection to [%s:%s] has failed", hostname, port)
|
||||||
}
|
}
|
||||||
isRunning = true
|
isRunning = true
|
||||||
|
|
@ -232,21 +232,21 @@ class RemoteClient(val hostname: String, val port: Int) extends Logging {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val exception = new IllegalStateException("Remote client is not running, make sure you have invoked 'RemoteClient.connect' before using it.")
|
val exception = new IllegalStateException("Remote client is not running, make sure you have invoked 'RemoteClient.connect' before using it.")
|
||||||
listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientError(exception))
|
listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientError(exception))
|
||||||
throw exception
|
throw exception
|
||||||
}
|
}
|
||||||
|
|
||||||
def registerSupervisorForActor(actor: Actor) =
|
def registerSupervisorForActor(actorId: ActorID) =
|
||||||
if (!actor._supervisor.isDefined) throw new IllegalStateException("Can't register supervisor for " + actor + " since it is not under supervision")
|
if (!actorId.supervisor.isDefined) throw new IllegalStateException("Can't register supervisor for " + actorId + " since it is not under supervision")
|
||||||
else supervisors.putIfAbsent(actor._supervisor.get.uuid, actor)
|
else supervisors.putIfAbsent(actorId.supervisor.get.uuid, actorId)
|
||||||
|
|
||||||
def deregisterSupervisorForActor(actor: Actor) =
|
def deregisterSupervisorForActor(actorId: ActorID) =
|
||||||
if (!actor._supervisor.isDefined) throw new IllegalStateException("Can't unregister supervisor for " + actor + " since it is not under supervision")
|
if (!actorId.supervisor.isDefined) throw new IllegalStateException("Can't unregister supervisor for " + actorId + " since it is not under supervision")
|
||||||
else supervisors.remove(actor._supervisor.get.uuid)
|
else supervisors.remove(actorId.supervisor.get.uuid)
|
||||||
|
|
||||||
def registerListener(actor: Actor) = listeners.add(actor)
|
def registerListener(actorId: ActorID) = listeners.add(actorId)
|
||||||
|
|
||||||
def deregisterListener(actor: Actor) = listeners.remove(actor)
|
def deregisterListener(actorId: ActorID) = listeners.remove(actorId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -254,7 +254,7 @@ class RemoteClient(val hostname: String, val port: Int) extends Logging {
|
||||||
*/
|
*/
|
||||||
class RemoteClientPipelineFactory(name: String,
|
class RemoteClientPipelineFactory(name: String,
|
||||||
futures: ConcurrentMap[Long, CompletableFuture[_]],
|
futures: ConcurrentMap[Long, CompletableFuture[_]],
|
||||||
supervisors: ConcurrentMap[String, Actor],
|
supervisors: ConcurrentMap[String, ActorID],
|
||||||
bootstrap: ClientBootstrap,
|
bootstrap: ClientBootstrap,
|
||||||
remoteAddress: SocketAddress,
|
remoteAddress: SocketAddress,
|
||||||
timer: HashedWheelTimer,
|
timer: HashedWheelTimer,
|
||||||
|
|
@ -285,7 +285,7 @@ class RemoteClientPipelineFactory(name: String,
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
class RemoteClientHandler(val name: String,
|
class RemoteClientHandler(val name: String,
|
||||||
val futures: ConcurrentMap[Long, CompletableFuture[_]],
|
val futures: ConcurrentMap[Long, CompletableFuture[_]],
|
||||||
val supervisors: ConcurrentMap[String, Actor],
|
val supervisors: ConcurrentMap[String, ActorID],
|
||||||
val bootstrap: ClientBootstrap,
|
val bootstrap: ClientBootstrap,
|
||||||
val remoteAddress: SocketAddress,
|
val remoteAddress: SocketAddress,
|
||||||
val timer: HashedWheelTimer,
|
val timer: HashedWheelTimer,
|
||||||
|
|
@ -316,21 +316,21 @@ class RemoteClientHandler(val name: String,
|
||||||
if (!supervisors.containsKey(supervisorUuid))
|
if (!supervisors.containsKey(supervisorUuid))
|
||||||
throw new IllegalStateException("Expected a registered supervisor for UUID [" + supervisorUuid + "] but none was found")
|
throw new IllegalStateException("Expected a registered supervisor for UUID [" + supervisorUuid + "] but none was found")
|
||||||
val supervisedActor = supervisors.get(supervisorUuid)
|
val supervisedActor = supervisors.get(supervisorUuid)
|
||||||
if (!supervisedActor._supervisor.isDefined)
|
if (!supervisedActor.supervisor.isDefined)
|
||||||
throw new IllegalStateException("Can't handle restart for remote actor " + supervisedActor + " since its supervisor has been removed")
|
throw new IllegalStateException("Can't handle restart for remote actor " + supervisedActor + " since its supervisor has been removed")
|
||||||
else supervisedActor._supervisor.get ! Exit(supervisedActor, parseException(reply))
|
else supervisedActor.supervisor.get ! Exit(supervisedActor, parseException(reply))
|
||||||
}
|
}
|
||||||
future.completeWithException(null, parseException(reply))
|
future.completeWithException(null, parseException(reply))
|
||||||
}
|
}
|
||||||
futures.remove(reply.getId)
|
futures.remove(reply.getId)
|
||||||
} else {
|
} else {
|
||||||
val exception = new IllegalArgumentException("Unknown message received in remote client handler: " + result)
|
val exception = new IllegalArgumentException("Unknown message received in remote client handler: " + result)
|
||||||
client.listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientError(exception))
|
client.listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientError(exception))
|
||||||
throw exception
|
throw exception
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case e: Exception =>
|
case e: Exception =>
|
||||||
client.listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientError(e))
|
client.listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientError(e))
|
||||||
log.error("Unexpected exception in remote client handler: %s", e)
|
log.error("Unexpected exception in remote client handler: %s", e)
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +345,7 @@ class RemoteClientHandler(val name: String,
|
||||||
// Wait until the connection attempt succeeds or fails.
|
// Wait until the connection attempt succeeds or fails.
|
||||||
client.connection.awaitUninterruptibly
|
client.connection.awaitUninterruptibly
|
||||||
if (!client.connection.isSuccess) {
|
if (!client.connection.isSuccess) {
|
||||||
client.listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientError(client.connection.getCause))
|
client.listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientError(client.connection.getCause))
|
||||||
log.error(client.connection.getCause, "Reconnection to [%s] has failed", remoteAddress)
|
log.error(client.connection.getCause, "Reconnection to [%s] has failed", remoteAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -353,17 +353,17 @@ class RemoteClientHandler(val name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = {
|
override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = {
|
||||||
client.listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientConnected(client.hostname, client.port))
|
client.listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientConnected(client.hostname, client.port))
|
||||||
log.debug("Remote client connected to [%s]", ctx.getChannel.getRemoteAddress)
|
log.debug("Remote client connected to [%s]", ctx.getChannel.getRemoteAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = {
|
override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = {
|
||||||
client.listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientDisconnected(client.hostname, client.port))
|
client.listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientDisconnected(client.hostname, client.port))
|
||||||
log.debug("Remote client disconnected from [%s]", ctx.getChannel.getRemoteAddress)
|
log.debug("Remote client disconnected from [%s]", ctx.getChannel.getRemoteAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def exceptionCaught(ctx: ChannelHandlerContext, event: ExceptionEvent) = {
|
override def exceptionCaught(ctx: ChannelHandlerContext, event: ExceptionEvent) = {
|
||||||
client.listeners.toArray.foreach(l => l.asInstanceOf[Actor] ! RemoteClientError(event.getCause))
|
client.listeners.toArray.foreach(l => l.asInstanceOf[ActorID] ! RemoteClientError(event.getCause))
|
||||||
log.error(event.getCause, "Unexpected exception from downstream in remote client")
|
log.error(event.getCause, "Unexpected exception from downstream in remote client")
|
||||||
event.getChannel.close
|
event.getChannel.close
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ class RemoteServer extends Logging {
|
||||||
/**
|
/**
|
||||||
* Register Remote Actor by the Actor's 'id' field.
|
* Register Remote Actor by the Actor's 'id' field.
|
||||||
*/
|
*/
|
||||||
def register(actor: Actor) = synchronized {
|
def register(actor: ActorID) = synchronized {
|
||||||
if (_isRunning) {
|
if (_isRunning) {
|
||||||
log.info("Registering server side remote actor [%s] with id [%s]", actor.getClass.getName, actor.getId)
|
log.info("Registering server side remote actor [%s] with id [%s]", actor.getClass.getName, actor.getId)
|
||||||
RemoteServer.actorsFor(RemoteServer.Address(hostname, port)).actors.put(actor.getId, actor)
|
RemoteServer.actorsFor(RemoteServer.Address(hostname, port)).actors.put(actor.getId, actor)
|
||||||
|
|
@ -208,7 +208,7 @@ class RemoteServer extends Logging {
|
||||||
/**
|
/**
|
||||||
* Register Remote Actor by a specific 'id' passed as argument.
|
* Register Remote Actor by a specific 'id' passed as argument.
|
||||||
*/
|
*/
|
||||||
def register(id: String, actor: Actor) = synchronized {
|
def register(id: String, actor: ActorID) = synchronized {
|
||||||
if (_isRunning) {
|
if (_isRunning) {
|
||||||
log.info("Registering server side remote actor [%s] with id [%s]", actor.getClass.getName, id)
|
log.info("Registering server side remote actor [%s] with id [%s]", actor.getClass.getName, id)
|
||||||
RemoteServer.actorsFor(RemoteServer.Address(hostname, port)).actors.put(id, actor)
|
RemoteServer.actorsFor(RemoteServer.Address(hostname, port)).actors.put(id, actor)
|
||||||
|
|
@ -225,7 +225,7 @@ class RemoteServerPipelineFactory(
|
||||||
val name: String,
|
val name: String,
|
||||||
val openChannels: ChannelGroup,
|
val openChannels: ChannelGroup,
|
||||||
val loader: Option[ClassLoader],
|
val loader: Option[ClassLoader],
|
||||||
val actors: JMap[String, Actor],
|
val actors: JMap[String, ActorID],
|
||||||
val activeObjects: JMap[String, AnyRef]) extends ChannelPipelineFactory {
|
val activeObjects: JMap[String, AnyRef]) extends ChannelPipelineFactory {
|
||||||
import RemoteServer._
|
import RemoteServer._
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ class RemoteServerHandler(
|
||||||
val name: String,
|
val name: String,
|
||||||
val openChannels: ChannelGroup,
|
val openChannels: ChannelGroup,
|
||||||
val applicationLoader: Option[ClassLoader],
|
val applicationLoader: Option[ClassLoader],
|
||||||
val actors: JMap[String, Actor],
|
val actors: JMap[String, ActorID],
|
||||||
val activeObjects: JMap[String, AnyRef]) extends SimpleChannelUpstreamHandler with Logging {
|
val activeObjects: JMap[String, AnyRef]) extends SimpleChannelUpstreamHandler with Logging {
|
||||||
val AW_PROXY_PREFIX = "$$ProxiedByAW".intern
|
val AW_PROXY_PREFIX = "$$ProxiedByAW".intern
|
||||||
|
|
||||||
|
|
@ -300,8 +300,8 @@ class RemoteServerHandler(
|
||||||
|
|
||||||
private def dispatchToActor(request: RemoteRequest, channel: Channel) = {
|
private def dispatchToActor(request: RemoteRequest, channel: Channel) = {
|
||||||
log.debug("Dispatching to remote actor [%s]", request.getTarget)
|
log.debug("Dispatching to remote actor [%s]", request.getTarget)
|
||||||
val actor = createActor(request.getTarget, request.getUuid, request.getTimeout)
|
val actorId = createActor(request.getTarget, request.getUuid, request.getTimeout)
|
||||||
actor.start
|
actorId.start
|
||||||
|
|
||||||
val message = RemoteProtocolBuilder.getMessage(request)
|
val message = RemoteProtocolBuilder.getMessage(request)
|
||||||
if (request.getIsOneWay) {
|
if (request.getIsOneWay) {
|
||||||
|
|
@ -310,19 +310,19 @@ class RemoteServerHandler(
|
||||||
val targetClass = if (request.hasSourceTarget) request.getSourceTarget
|
val targetClass = if (request.hasSourceTarget) request.getSourceTarget
|
||||||
else request.getTarget
|
else request.getTarget
|
||||||
|
|
||||||
val remoteActor = createActor(targetClass, request.getSourceUuid, request.getTimeout)
|
val remoteActorId = createActor(targetClass, request.getSourceUuid, request.getTimeout)
|
||||||
if (!remoteActor.isRunning) {
|
if (!remoteActorId.isRunning) {
|
||||||
remoteActor.makeRemote(request.getSourceHostname, request.getSourcePort)
|
remoteActorId.makeRemote(request.getSourceHostname, request.getSourcePort)
|
||||||
remoteActor.start
|
remoteActorId.start
|
||||||
}
|
}
|
||||||
actor.!(message)(Some(remoteActor))
|
actorId.!(message)(Some(remoteActorId))
|
||||||
} else {
|
} else {
|
||||||
// couldn't find a way to reply, send the message without a source/sender
|
// couldn't find a way to reply, send the message without a source/sender
|
||||||
actor ! message
|
actorId ! message
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
val resultOrNone = actor !! message
|
val resultOrNone = actorId !! message
|
||||||
val result: AnyRef = if (resultOrNone.isDefined) resultOrNone.get else null
|
val result: AnyRef = if (resultOrNone.isDefined) resultOrNone.get else null
|
||||||
log.debug("Returning result from actor invocation [%s]", result)
|
log.debug("Returning result from actor invocation [%s]", result)
|
||||||
val replyBuilder = RemoteReply.newBuilder
|
val replyBuilder = RemoteReply.newBuilder
|
||||||
|
|
@ -440,9 +440,9 @@ class RemoteServerHandler(
|
||||||
* If actor already created then just return it from the registry.
|
* If actor already created then just return it from the registry.
|
||||||
* Does not start the actor.
|
* Does not start the actor.
|
||||||
*/
|
*/
|
||||||
private def createActor(name: String, uuid: String, timeout: Long): Actor = {
|
private def createActor(name: String, uuid: String, timeout: Long): ActorID = {
|
||||||
val actorOrNull = actors.get(uuid)
|
val actorIdOrNull = actors.get(uuid)
|
||||||
if (actorOrNull eq null) {
|
if (actorIdOrNull eq null) {
|
||||||
try {
|
try {
|
||||||
log.info("Creating a new remote actor [%s:%s]", name, uuid)
|
log.info("Creating a new remote actor [%s:%s]", name, uuid)
|
||||||
val clazz = if (applicationLoader.isDefined) applicationLoader.get.loadClass(name)
|
val clazz = if (applicationLoader.isDefined) applicationLoader.get.loadClass(name)
|
||||||
|
|
@ -451,13 +451,14 @@ class RemoteServerHandler(
|
||||||
newInstance._uuid = uuid
|
newInstance._uuid = uuid
|
||||||
newInstance.timeout = timeout
|
newInstance.timeout = timeout
|
||||||
newInstance._remoteAddress = None
|
newInstance._remoteAddress = None
|
||||||
actors.put(uuid, newInstance)
|
val actorId = new ActorID(() => newInstance)
|
||||||
newInstance
|
actors.put(uuid, actorId)
|
||||||
|
actorId
|
||||||
} catch {
|
} catch {
|
||||||
case e =>
|
case e =>
|
||||||
log.error(e, "Could not create remote actor instance")
|
log.error(e, "Could not create remote actor instance")
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
} else actorOrNull
|
} else actorIdOrNull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ package se.scalablesolutions.akka.stm
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import java.util.concurrent.{ConcurrentLinkedQueue, LinkedBlockingQueue}
|
import java.util.concurrent.{ConcurrentLinkedQueue, LinkedBlockingQueue}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.{Actor, ActorID}
|
||||||
import se.scalablesolutions.akka.dispatch.CompletableFuture
|
import se.scalablesolutions.akka.dispatch.CompletableFuture
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -26,7 +26,7 @@ import se.scalablesolutions.akka.actor.Actor
|
||||||
import se.scalablesolutions.akka.dispatch.CompletableFuture
|
import se.scalablesolutions.akka.dispatch.CompletableFuture
|
||||||
|
|
||||||
def thread(body: => Unit) = {
|
def thread(body: => Unit) = {
|
||||||
val thread = new IsolatedEventBasedThread(body).start
|
val thread = new ActorID(() => new IsolatedEventBasedThread(body)).start
|
||||||
thread ! Start
|
thread ! Start
|
||||||
thread
|
thread
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +60,7 @@ import se.scalablesolutions.akka.dispatch.CompletableFuture
|
||||||
private case object Get extends DataFlowVariableMessage
|
private case object Get extends DataFlowVariableMessage
|
||||||
|
|
||||||
private val value = new AtomicReference[Option[T]](None)
|
private val value = new AtomicReference[Option[T]](None)
|
||||||
private val blockedReaders = new ConcurrentLinkedQueue[Actor]
|
private val blockedReaders = new ConcurrentLinkedQueue[ActorID]
|
||||||
|
|
||||||
private class In[T <: Any](dataFlow: DataFlowVariable[T]) extends Actor {
|
private class In[T <: Any](dataFlow: DataFlowVariable[T]) extends Actor {
|
||||||
timeout = TIME_OUT
|
timeout = TIME_OUT
|
||||||
|
|
@ -97,7 +97,7 @@ import se.scalablesolutions.akka.dispatch.CompletableFuture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] val in = new In(this)
|
private[this] val in = new ActorID(() => new In(this))
|
||||||
|
|
||||||
def <<(ref: DataFlowVariable[T]) = in ! Set(ref())
|
def <<(ref: DataFlowVariable[T]) = in ! Set(ref())
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ import se.scalablesolutions.akka.dispatch.CompletableFuture
|
||||||
val ref = value.get
|
val ref = value.get
|
||||||
if (ref.isDefined) ref.get
|
if (ref.isDefined) ref.get
|
||||||
else {
|
else {
|
||||||
val out = new Out(this)
|
val out = new ActorID(() => new Out(this))
|
||||||
blockedReaders.offer(out)
|
blockedReaders.offer(out)
|
||||||
val result = out !! Get
|
val result = out !! Get
|
||||||
out ! Exit
|
out ! Exit
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ActorFireForgetRequestReplySpec extends JUnitSuite {
|
class ActorFireForgetRequestReplySpec extends JUnitSuite {
|
||||||
|
|
||||||
|
|
@ -22,7 +23,7 @@ class ActorFireForgetRequestReplySpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SenderActor(replyActor: Actor) extends Actor {
|
class SenderActor(replyActor: ActorID) extends Actor {
|
||||||
dispatcher = Dispatchers.newThreadBasedDispatcher(this)
|
dispatcher = Dispatchers.newThreadBasedDispatcher(this)
|
||||||
|
|
||||||
def receive = {
|
def receive = {
|
||||||
|
|
@ -41,11 +42,9 @@ class ActorFireForgetRequestReplySpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldReplyToBangMessageUsingReply = {
|
def shouldReplyToBangMessageUsingReply = {
|
||||||
import Actor.Sender.Self
|
val replyActor = newActor[ReplyActor]
|
||||||
|
|
||||||
val replyActor = new ReplyActor
|
|
||||||
replyActor.start
|
replyActor.start
|
||||||
val senderActor = new SenderActor(replyActor)
|
val senderActor = newActor(() => new SenderActor(replyActor))
|
||||||
senderActor.start
|
senderActor.start
|
||||||
senderActor ! "Init"
|
senderActor ! "Init"
|
||||||
assert(state.finished.await(1, TimeUnit.SECONDS))
|
assert(state.finished.await(1, TimeUnit.SECONDS))
|
||||||
|
|
@ -54,11 +53,9 @@ class ActorFireForgetRequestReplySpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldReplyToBangMessageUsingImplicitSender = {
|
def shouldReplyToBangMessageUsingImplicitSender = {
|
||||||
import Actor.Sender.Self
|
val replyActor = newActor[ReplyActor]
|
||||||
|
|
||||||
val replyActor = new ReplyActor
|
|
||||||
replyActor.start
|
replyActor.start
|
||||||
val senderActor = new SenderActor(replyActor)
|
val senderActor = newActor(() => new SenderActor(replyActor))
|
||||||
senderActor.start
|
senderActor.start
|
||||||
senderActor ! "InitImplicit"
|
senderActor ! "InitImplicit"
|
||||||
assert(state.finished.await(1, TimeUnit.SECONDS))
|
assert(state.finished.await(1, TimeUnit.SECONDS))
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package se.scalablesolutions.akka.actor
|
||||||
|
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ActorRegistrySpec extends JUnitSuite {
|
class ActorRegistrySpec extends JUnitSuite {
|
||||||
var record = ""
|
var record = ""
|
||||||
|
|
@ -16,18 +17,18 @@ class ActorRegistrySpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test def shouldGetActorByIdFromActorRegistry = {
|
@Test def shouldGetActorByIdFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val actors = ActorRegistry.actorsFor("MyID")
|
val actors = ActorRegistry.actorsFor("MyID")
|
||||||
assert(actors.size === 1)
|
assert(actors.size === 1)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId == "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor.stop
|
actor.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetActorByUUIDFromActorRegistry = {
|
@Test def shouldGetActorByUUIDFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
val uuid = actor.uuid
|
val uuid = actor.uuid
|
||||||
actor.start
|
actor.start
|
||||||
val actorOrNone = ActorRegistry.actorFor(uuid)
|
val actorOrNone = ActorRegistry.actorFor(uuid)
|
||||||
|
|
@ -38,95 +39,95 @@ class ActorRegistrySpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test def shouldGetActorByClassFromActorRegistry = {
|
@Test def shouldGetActorByClassFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val actors = ActorRegistry.actorsFor(classOf[TestActor])
|
val actors = ActorRegistry.actorsFor(classOf[TestActor])
|
||||||
assert(actors.size === 1)
|
assert(actors.size === 1)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId === "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor.stop
|
actor.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetActorByManifestFromActorRegistry = {
|
@Test def shouldGetActorByManifestFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val actors: List[TestActor] = ActorRegistry.actorsFor[TestActor]
|
val actors = ActorRegistry.actorsFor[TestActor]
|
||||||
assert(actors.size === 1)
|
assert(actors.size === 1)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId === "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor.stop
|
actor.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetActorsByIdFromActorRegistry = {
|
@Test def shouldGetActorsByIdFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val actors = ActorRegistry.actorsFor("MyID")
|
val actors = ActorRegistry.actorsFor("MyID")
|
||||||
assert(actors.size === 2)
|
assert(actors.size === 2)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId === "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
assert(actors.last.isInstanceOf[TestActor])
|
assert(actors.last.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.last.getId === "MyID")
|
assert(actors.last.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor1.stop
|
actor1.stop
|
||||||
actor2.stop
|
actor2.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetActorsByClassFromActorRegistry = {
|
@Test def shouldGetActorsByClassFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val actors = ActorRegistry.actorsFor(classOf[TestActor])
|
val actors = ActorRegistry.actorsFor(classOf[TestActor])
|
||||||
assert(actors.size === 2)
|
assert(actors.size === 2)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId === "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
assert(actors.last.isInstanceOf[TestActor])
|
assert(actors.last.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.last.getId === "MyID")
|
assert(actors.last.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor1.stop
|
actor1.stop
|
||||||
actor2.stop
|
actor2.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetActorsByManifestFromActorRegistry = {
|
@Test def shouldGetActorsByManifestFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val actors: List[TestActor] = ActorRegistry.actorsFor[TestActor]
|
val actors = ActorRegistry.actorsFor[TestActor]
|
||||||
assert(actors.size === 2)
|
assert(actors.size === 2)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId === "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
assert(actors.last.isInstanceOf[TestActor])
|
assert(actors.last.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.last.getId === "MyID")
|
assert(actors.last.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor1.stop
|
actor1.stop
|
||||||
actor2.stop
|
actor2.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetAllActorsFromActorRegistry = {
|
@Test def shouldGetAllActorsFromActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val actors = ActorRegistry.actors
|
val actors = ActorRegistry.actors
|
||||||
assert(actors.size === 2)
|
assert(actors.size === 2)
|
||||||
assert(actors.head.isInstanceOf[TestActor])
|
assert(actors.head.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.head.getId === "MyID")
|
assert(actors.head.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
assert(actors.last.isInstanceOf[TestActor])
|
assert(actors.last.actor.isInstanceOf[TestActor])
|
||||||
assert(actors.last.getId === "MyID")
|
assert(actors.last.actor.asInstanceOf[TestActor].getId === "MyID")
|
||||||
actor1.stop
|
actor1.stop
|
||||||
actor2.stop
|
actor2.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldGetResponseByAllActorsInActorRegistryWhenInvokingForeach = {
|
@Test def shouldGetResponseByAllActorsInActorRegistryWhenInvokingForeach = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
record = ""
|
record = ""
|
||||||
ActorRegistry.foreach(actor => actor !! "ping")
|
ActorRegistry.foreach(actor => actor !! "ping")
|
||||||
|
|
@ -137,9 +138,9 @@ class ActorRegistrySpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test def shouldShutdownAllActorsInActorRegistry = {
|
@Test def shouldShutdownAllActorsInActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
assert(ActorRegistry.actors.size === 0)
|
assert(ActorRegistry.actors.size === 0)
|
||||||
|
|
@ -147,9 +148,9 @@ class ActorRegistrySpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test def shouldRemoveUnregisterActorInActorRegistry = {
|
@Test def shouldRemoveUnregisterActorInActorRegistry = {
|
||||||
ActorRegistry.shutdownAll
|
ActorRegistry.shutdownAll
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
assert(ActorRegistry.actors.size === 2)
|
assert(ActorRegistry.actors.size === 2)
|
||||||
ActorRegistry.unregister(actor1)
|
ActorRegistry.unregister(actor1)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package se.scalablesolutions.akka.actor
|
||||||
import se.scalablesolutions.akka.actor.Actor.transactor
|
import se.scalablesolutions.akka.actor.Actor.transactor
|
||||||
import se.scalablesolutions.akka.stm.Transaction.Global.atomic
|
import se.scalablesolutions.akka.stm.Transaction.Global.atomic
|
||||||
import se.scalablesolutions.akka.util.Logging
|
import se.scalablesolutions.akka.util.Logging
|
||||||
|
import Actor._
|
||||||
|
|
||||||
import org.scalatest.Suite
|
import org.scalatest.Suite
|
||||||
import org.scalatest.junit.JUnitRunner
|
import org.scalatest.junit.JUnitRunner
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import org.junit.{Test, Before, After}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.remote.{RemoteServer, RemoteClient}
|
import se.scalablesolutions.akka.remote.{RemoteServer, RemoteClient}
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
case class Send(actor: Actor)
|
case class Send(actor: Actor)
|
||||||
|
|
||||||
|
|
@ -44,7 +45,7 @@ object SendOneWayAndReplySenderActor {
|
||||||
}
|
}
|
||||||
class SendOneWayAndReplySenderActor extends Actor {
|
class SendOneWayAndReplySenderActor extends Actor {
|
||||||
var state: Option[AnyRef] = None
|
var state: Option[AnyRef] = None
|
||||||
var sendTo: Actor = _
|
var sendTo: ActorID = _
|
||||||
var latch: CountDownLatch = _
|
var latch: CountDownLatch = _
|
||||||
|
|
||||||
def sendOff = sendTo ! "Hello"
|
def sendOff = sendTo ! "Hello"
|
||||||
|
|
@ -89,7 +90,7 @@ class ClientInitiatedRemoteActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldSendOneWay = {
|
def shouldSendOneWay = {
|
||||||
val actor = new RemoteActorSpecActorUnidirectional
|
val actor = newActor[RemoteActorSpecActorUnidirectional]
|
||||||
actor.makeRemote(HOSTNAME, PORT1)
|
actor.makeRemote(HOSTNAME, PORT1)
|
||||||
actor.start
|
actor.start
|
||||||
actor ! "OneWay"
|
actor ! "OneWay"
|
||||||
|
|
@ -99,24 +100,24 @@ class ClientInitiatedRemoteActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldSendOneWayAndReceiveReply = {
|
def shouldSendOneWayAndReceiveReply = {
|
||||||
val actor = new SendOneWayAndReplyReceiverActor
|
val actor = newActor[SendOneWayAndReplyReceiverActor]
|
||||||
actor.makeRemote(HOSTNAME, PORT1)
|
actor.makeRemote(HOSTNAME, PORT1)
|
||||||
actor.start
|
actor.start
|
||||||
val sender = new SendOneWayAndReplySenderActor
|
val sender = newActor[SendOneWayAndReplySenderActor]
|
||||||
sender.setReplyToAddress(HOSTNAME, PORT2)
|
sender.setReplyToAddress(HOSTNAME, PORT2)
|
||||||
sender.sendTo = actor
|
sender.actor.asInstanceOf[SendOneWayAndReplySenderActor].sendTo = actor
|
||||||
sender.start
|
sender.start
|
||||||
sender.sendOff
|
sender.actor.asInstanceOf[SendOneWayAndReplySenderActor].sendOff
|
||||||
assert(SendOneWayAndReplySenderActor.latch.await(1, TimeUnit.SECONDS))
|
assert(SendOneWayAndReplySenderActor.latch.await(1, TimeUnit.SECONDS))
|
||||||
assert(sender.state.isDefined === true)
|
assert(sender.actor.asInstanceOf[SendOneWayAndReplySenderActor].state.isDefined === true)
|
||||||
assert("World" === sender.state.get.asInstanceOf[String])
|
assert("World" === sender.actor.asInstanceOf[SendOneWayAndReplySenderActor].state.get.asInstanceOf[String])
|
||||||
actor.stop
|
actor.stop
|
||||||
sender.stop
|
sender.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldSendBangBangMessageAndReceiveReply = {
|
def shouldSendBangBangMessageAndReceiveReply = {
|
||||||
val actor = new RemoteActorSpecActorBidirectional
|
val actor = newActor[RemoteActorSpecActorBidirectional]
|
||||||
actor.makeRemote(HOSTNAME, PORT1)
|
actor.makeRemote(HOSTNAME, PORT1)
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor !! "Hello"
|
val result = actor !! "Hello"
|
||||||
|
|
@ -127,7 +128,7 @@ class ClientInitiatedRemoteActorSpec extends JUnitSuite {
|
||||||
@Test
|
@Test
|
||||||
def shouldSendAndReceiveRemoteException = {
|
def shouldSendAndReceiveRemoteException = {
|
||||||
implicit val timeout = 500000000L
|
implicit val timeout = 500000000L
|
||||||
val actor = new RemoteActorSpecActorBidirectional
|
val actor = newActor[RemoteActorSpecActorBidirectional]
|
||||||
actor.makeRemote(HOSTNAME, PORT1)
|
actor.makeRemote(HOSTNAME, PORT1)
|
||||||
actor.start
|
actor.start
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ExecutorBasedEventDrivenDispatcherActorSpec extends JUnitSuite {
|
class ExecutorBasedEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
import Actor.Sender.Self
|
import Actor.Sender.Self
|
||||||
|
|
@ -20,22 +21,26 @@ class ExecutorBasedEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendOneWay = {
|
object OneWayTestActor {
|
||||||
val oneWay = new CountDownLatch(1)
|
val oneWay = new CountDownLatch(1)
|
||||||
val actor = new Actor {
|
}
|
||||||
dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher(uuid)
|
class OneWayTestActor extends Actor {
|
||||||
def receive = {
|
dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher(uuid)
|
||||||
case "OneWay" => oneWay.countDown
|
def receive = {
|
||||||
}
|
case "OneWay" => OneWayTestActor.oneWay.countDown
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test def shouldSendOneWay = {
|
||||||
|
val actor = newActor[OneWayTestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor ! "OneWay"
|
val result = actor ! "OneWay"
|
||||||
assert(oneWay.await(1, TimeUnit.SECONDS))
|
assert(OneWayTestActor.oneWay.await(1, TimeUnit.SECONDS))
|
||||||
actor.stop
|
actor.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplySync = {
|
@Test def shouldSendReplySync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result: String = (actor !! ("Hello", 10000)).get
|
val result: String = (actor !! ("Hello", 10000)).get
|
||||||
assert("World" === result)
|
assert("World" === result)
|
||||||
|
|
@ -43,7 +48,7 @@ class ExecutorBasedEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplyAsync = {
|
@Test def shouldSendReplyAsync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor !! "Hello"
|
val result = actor !! "Hello"
|
||||||
assert("World" === result.get.asInstanceOf[String])
|
assert("World" === result.get.asInstanceOf[String])
|
||||||
|
|
@ -51,7 +56,7 @@ class ExecutorBasedEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReceiveException = {
|
@Test def shouldSendReceiveException = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
try {
|
try {
|
||||||
actor !! "Failure"
|
actor !! "Failure"
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,14 @@ import org.junit.Test
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
import org.scalatest.matchers.MustMatchers
|
import org.scalatest.matchers.MustMatchers
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import Actor._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the behaviour of the executor based event driven dispatcher when multiple actors are being dispatched on it.
|
* Tests the behaviour of the executor based event driven dispatcher when multiple actors are being dispatched on it.
|
||||||
*
|
*
|
||||||
* @author Jan Van Besien
|
* @author Jan Van Besien
|
||||||
*/
|
*/
|
||||||
class ExecutorBasedEventDrivenDispatcherActorsSpec extends JUnitSuite with MustMatchers with ActorTestUtil {
|
class ExecutorBasedEventDrivenDispatcherActorsSpec extends JUnitSuite with MustMatchers {
|
||||||
class SlowActor(finishedCounter: CountDownLatch) extends Actor {
|
class SlowActor(finishedCounter: CountDownLatch) extends Actor {
|
||||||
messageDispatcher = Dispatchers.globalExecutorBasedEventDrivenDispatcher
|
messageDispatcher = Dispatchers.globalExecutorBasedEventDrivenDispatcher
|
||||||
id = "SlowActor"
|
id = "SlowActor"
|
||||||
|
|
@ -35,29 +36,26 @@ class ExecutorBasedEventDrivenDispatcherActorsSpec extends JUnitSuite with MustM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def slowActorShouldntBlockFastActor = verify(new TestActor {
|
@Test def slowActorShouldntBlockFastActor = {
|
||||||
def test = {
|
val sFinished = new CountDownLatch(50)
|
||||||
val sFinished = new CountDownLatch(50)
|
val fFinished = new CountDownLatch(10)
|
||||||
val fFinished = new CountDownLatch(10)
|
val s = newActor(() => new SlowActor(sFinished)).start
|
||||||
val s = new SlowActor(sFinished)
|
val f = newActor(() => new FastActor(fFinished)).start
|
||||||
val f = new FastActor(fFinished)
|
|
||||||
|
|
||||||
handle(s, f) {
|
// send a lot of stuff to s
|
||||||
// send a lot of stuff to s
|
for (i <- 1 to 50) {
|
||||||
for (i <- 1 to 50) {
|
s ! i
|
||||||
s ! i
|
|
||||||
}
|
|
||||||
|
|
||||||
// send some messages to f
|
|
||||||
for (i <- 1 to 10) {
|
|
||||||
f ! i
|
|
||||||
}
|
|
||||||
|
|
||||||
// now assert that f is finished while s is still busy
|
|
||||||
fFinished.await
|
|
||||||
assert(sFinished.getCount > 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
|
// send some messages to f
|
||||||
|
for (i <- 1 to 10) {
|
||||||
|
f ! i
|
||||||
|
}
|
||||||
|
|
||||||
|
// now assert that f is finished while s is still busy
|
||||||
|
fFinished.await
|
||||||
|
assert(sFinished.getCount > 0)
|
||||||
|
f.stop
|
||||||
|
s.stop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@ import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
import java.util.concurrent.{TimeUnit, CountDownLatch}
|
import java.util.concurrent.{TimeUnit, CountDownLatch}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jan Van Besien
|
* @author Jan Van Besien
|
||||||
*/
|
*/
|
||||||
class ExecutorBasedEventDrivenWorkStealingDispatcherSpec extends JUnitSuite with MustMatchers with ActorTestUtil {
|
class ExecutorBasedEventDrivenWorkStealingDispatcherSpec extends JUnitSuite with MustMatchers {
|
||||||
val poolDispatcher = Dispatchers.newExecutorBasedEventDrivenWorkStealingDispatcher("pooled-dispatcher")
|
val poolDispatcher = Dispatchers.newExecutorBasedEventDrivenWorkStealingDispatcher("pooled-dispatcher")
|
||||||
|
|
||||||
class DelayableActor(name: String, delay: Int, finishedCounter: CountDownLatch) extends Actor {
|
class DelayableActor(name: String, delay: Int, finishedCounter: CountDownLatch) extends Actor {
|
||||||
|
|
@ -29,40 +30,38 @@ class ExecutorBasedEventDrivenWorkStealingDispatcherSpec extends JUnitSuite with
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def fastActorShouldStealWorkFromSlowActor = verify(new TestActor {
|
@Test def fastActorShouldStealWorkFromSlowActor = {
|
||||||
def test = {
|
val finishedCounter = new CountDownLatch(110)
|
||||||
val finishedCounter = new CountDownLatch(110)
|
|
||||||
|
|
||||||
val slow = new DelayableActor("slow", 50, finishedCounter)
|
val slow = newActor(() => new DelayableActor("slow", 50, finishedCounter)).start
|
||||||
val fast = new DelayableActor("fast", 10, finishedCounter)
|
val fast = newActor(() => new DelayableActor("fast", 10, finishedCounter)).start
|
||||||
|
|
||||||
handle(slow, fast) {
|
for (i <- 1 to 100) {
|
||||||
for (i <- 1 to 100) {
|
// send most work to slow actor
|
||||||
// send most work to slow actor
|
if (i % 20 == 0)
|
||||||
if (i % 20 == 0)
|
fast ! i
|
||||||
fast ! i
|
else
|
||||||
else
|
slow ! i
|
||||||
slow ! i
|
|
||||||
}
|
|
||||||
|
|
||||||
// now send some messages to actors to keep the dispatcher dispatching messages
|
|
||||||
for (i <- 1 to 10) {
|
|
||||||
Thread.sleep(150)
|
|
||||||
if (i % 2 == 0)
|
|
||||||
fast ! i
|
|
||||||
else
|
|
||||||
slow ! i
|
|
||||||
}
|
|
||||||
|
|
||||||
finishedCounter.await(5, TimeUnit.SECONDS)
|
|
||||||
fast.invocationCount must be > (slow.invocationCount)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
@Test def canNotUseActorsOfDifferentTypesInSameDispatcher:Unit = {
|
// now send some messages to actors to keep the dispatcher dispatching messages
|
||||||
val first = new FirstActor
|
for (i <- 1 to 10) {
|
||||||
val second = new SecondActor
|
Thread.sleep(150)
|
||||||
|
if (i % 2 == 0)
|
||||||
|
fast ! i
|
||||||
|
else
|
||||||
|
slow ! i
|
||||||
|
}
|
||||||
|
|
||||||
|
finishedCounter.await(5, TimeUnit.SECONDS)
|
||||||
|
fast.actor.asInstanceOf[DelayableActor].invocationCount must be > (slow.actor.asInstanceOf[DelayableActor].invocationCount)
|
||||||
|
slow.stop
|
||||||
|
fast.stop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test def canNotUseActorsOfDifferentTypesInSameDispatcher = {
|
||||||
|
val first = newActor[FirstActor]
|
||||||
|
val second = newActor[SecondActor]
|
||||||
|
|
||||||
first.start
|
first.start
|
||||||
intercept[IllegalStateException] {
|
intercept[IllegalStateException] {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ import java.util.concurrent.{TimeUnit, CountDownLatch}
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ForwardActorSpec extends JUnitSuite {
|
class ForwardActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
object ForwardState {
|
object ForwardState {
|
||||||
var sender: Actor = null
|
var sender: ActorID = null
|
||||||
val finished = new CountDownLatch(1)
|
val finished = new CountDownLatch(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,7 +25,7 @@ class ForwardActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
|
|
||||||
class ForwardActor extends Actor {
|
class ForwardActor extends Actor {
|
||||||
val receiverActor = new ReceiverActor
|
val receiverActor = newActor[ReceiverActor]
|
||||||
receiverActor.start
|
receiverActor.start
|
||||||
def receive = {
|
def receive = {
|
||||||
case "SendBang" => receiverActor.forward("SendBang")
|
case "SendBang" => receiverActor.forward("SendBang")
|
||||||
|
|
@ -33,7 +34,7 @@ class ForwardActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BangSenderActor extends Actor {
|
class BangSenderActor extends Actor {
|
||||||
val forwardActor = new ForwardActor
|
val forwardActor = newActor[ForwardActor]
|
||||||
forwardActor.start
|
forwardActor.start
|
||||||
forwardActor ! "SendBang"
|
forwardActor ! "SendBang"
|
||||||
def receive = {
|
def receive = {
|
||||||
|
|
@ -42,7 +43,7 @@ class ForwardActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BangBangSenderActor extends Actor {
|
class BangBangSenderActor extends Actor {
|
||||||
val forwardActor = new ForwardActor
|
val forwardActor = newActor[ForwardActor]
|
||||||
forwardActor.start
|
forwardActor.start
|
||||||
(forwardActor !! "SendBangBang") match {
|
(forwardActor !! "SendBangBang") match {
|
||||||
case Some(_) => {ForwardState.finished.countDown}
|
case Some(_) => {ForwardState.finished.countDown}
|
||||||
|
|
@ -55,7 +56,7 @@ class ForwardActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldForwardActorReferenceWhenInvokingForwardOnBang = {
|
def shouldForwardActorReferenceWhenInvokingForwardOnBang = {
|
||||||
val senderActor = new BangSenderActor
|
val senderActor = newActor[BangSenderActor]
|
||||||
senderActor.start
|
senderActor.start
|
||||||
assert(ForwardState.finished.await(2, TimeUnit.SECONDS))
|
assert(ForwardState.finished.await(2, TimeUnit.SECONDS))
|
||||||
assert(ForwardState.sender ne null)
|
assert(ForwardState.sender ne null)
|
||||||
|
|
@ -64,7 +65,7 @@ class ForwardActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldForwardActorReferenceWhenInvokingForwardOnBangBang = {
|
def shouldForwardActorReferenceWhenInvokingForwardOnBangBang = {
|
||||||
val senderActor = new BangBangSenderActor
|
val senderActor = newActor[BangBangSenderActor]
|
||||||
senderActor.start
|
senderActor.start
|
||||||
assert(ForwardState.finished.await(2, TimeUnit.SECONDS))
|
assert(ForwardState.finished.await(2, TimeUnit.SECONDS))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package se.scalablesolutions.akka.actor
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import se.scalablesolutions.akka.dispatch.Futures
|
import se.scalablesolutions.akka.dispatch.Futures
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class FutureSpec extends JUnitSuite {
|
class FutureSpec extends JUnitSuite {
|
||||||
class TestActor extends Actor {
|
class TestActor extends Actor {
|
||||||
|
|
@ -16,7 +17,7 @@ class FutureSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldActorReplyResultThroughExplicitFuture = {
|
@Test def shouldActorReplyResultThroughExplicitFuture = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val future = actor !!! "Hello"
|
val future = actor !!! "Hello"
|
||||||
future.await
|
future.await
|
||||||
|
|
@ -26,7 +27,7 @@ class FutureSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldActorReplyExceptionThroughExplicitFuture = {
|
@Test def shouldActorReplyExceptionThroughExplicitFuture = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val future = actor !!! "Failure"
|
val future = actor !!! "Failure"
|
||||||
future.await
|
future.await
|
||||||
|
|
@ -37,9 +38,9 @@ class FutureSpec extends JUnitSuite {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@Test def shouldFutureAwaitEitherLeft = {
|
@Test def shouldFutureAwaitEitherLeft = {
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val future1 = actor1 !!! "Hello"
|
val future1 = actor1 !!! "Hello"
|
||||||
val future2 = actor2 !!! "NoReply"
|
val future2 = actor2 !!! "NoReply"
|
||||||
|
|
@ -51,9 +52,9 @@ class FutureSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldFutureAwaitEitherRight = {
|
@Test def shouldFutureAwaitEitherRight = {
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val future1 = actor1 !!! "NoReply"
|
val future1 = actor1 !!! "NoReply"
|
||||||
val future2 = actor2 !!! "Hello"
|
val future2 = actor2 !!! "Hello"
|
||||||
|
|
@ -65,9 +66,9 @@ class FutureSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@Test def shouldFutureAwaitOneLeft = {
|
@Test def shouldFutureAwaitOneLeft = {
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val future1 = actor1 !!! "NoReply"
|
val future1 = actor1 !!! "NoReply"
|
||||||
val future2 = actor2 !!! "Hello"
|
val future2 = actor2 !!! "Hello"
|
||||||
|
|
@ -79,9 +80,9 @@ class FutureSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldFutureAwaitOneRight = {
|
@Test def shouldFutureAwaitOneRight = {
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val future1 = actor1 !!! "Hello"
|
val future1 = actor1 !!! "Hello"
|
||||||
val future2 = actor2 !!! "NoReply"
|
val future2 = actor2 !!! "NoReply"
|
||||||
|
|
@ -93,9 +94,9 @@ class FutureSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldFutureAwaitAll = {
|
@Test def shouldFutureAwaitAll = {
|
||||||
val actor1 = new TestActor
|
val actor1 = newActor[TestActor]
|
||||||
actor1.start
|
actor1.start
|
||||||
val actor2 = new TestActor
|
val actor2 = newActor[TestActor]
|
||||||
actor2.start
|
actor2.start
|
||||||
val future1 = actor1 !!! "Hello"
|
val future1 = actor1 !!! "Hello"
|
||||||
val future2 = actor2 !!! "Hello"
|
val future2 = actor2 !!! "Hello"
|
||||||
|
|
@ -107,5 +108,4 @@ class FutureSpec extends JUnitSuite {
|
||||||
actor1.stop
|
actor1.stop
|
||||||
actor2.stop
|
actor2.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import se.scalablesolutions.akka.stm.{TransactionalState, TransactionalMap, TransactionalRef, TransactionalVector}
|
import se.scalablesolutions.akka.stm.{TransactionalState, TransactionalMap, TransactionalRef, TransactionalVector}
|
||||||
|
import Actor._
|
||||||
|
|
||||||
case class GetMapState(key: String)
|
case class GetMapState(key: String)
|
||||||
case object GetVectorState
|
case object GetVectorState
|
||||||
|
|
@ -15,15 +16,18 @@ case class SetMapState(key: String, value: String)
|
||||||
case class SetVectorState(key: String)
|
case class SetVectorState(key: String)
|
||||||
case class SetRefState(key: String)
|
case class SetRefState(key: String)
|
||||||
case class Success(key: String, value: String)
|
case class Success(key: String, value: String)
|
||||||
case class Failure(key: String, value: String, failer: Actor)
|
case class Failure(key: String, value: String, failer: ActorID)
|
||||||
|
|
||||||
case class SetMapStateOneWay(key: String, value: String)
|
case class SetMapStateOneWay(key: String, value: String)
|
||||||
case class SetVectorStateOneWay(key: String)
|
case class SetVectorStateOneWay(key: String)
|
||||||
case class SetRefStateOneWay(key: String)
|
case class SetRefStateOneWay(key: String)
|
||||||
case class SuccessOneWay(key: String, value: String)
|
case class SuccessOneWay(key: String, value: String)
|
||||||
case class FailureOneWay(key: String, value: String, failer: Actor)
|
case class FailureOneWay(key: String, value: String, failer: ActorID)
|
||||||
|
|
||||||
class InMemStatefulActor(expectedInvocationCount:Int) extends Actor {
|
case object GetNotifier
|
||||||
|
case class Notifier(latch: CountDownLatch)
|
||||||
|
|
||||||
|
class InMemStatefulActor(expectedInvocationCount: Int) extends Actor {
|
||||||
def this() = this(0)
|
def this() = this(0)
|
||||||
timeout = 5000
|
timeout = 5000
|
||||||
makeTransactionRequired
|
makeTransactionRequired
|
||||||
|
|
@ -35,6 +39,8 @@ class InMemStatefulActor(expectedInvocationCount:Int) extends Actor {
|
||||||
private lazy val refState = TransactionalState.newRef[String]
|
private lazy val refState = TransactionalState.newRef[String]
|
||||||
|
|
||||||
def receive = {
|
def receive = {
|
||||||
|
case GetNotifier =>
|
||||||
|
reply(Notifier(notifier))
|
||||||
case GetMapState(key) =>
|
case GetMapState(key) =>
|
||||||
reply(mapState.get(key).get)
|
reply(mapState.get(key).get)
|
||||||
notifier.countDown
|
notifier.countDown
|
||||||
|
|
@ -105,17 +111,18 @@ class InMemFailerActor extends Actor {
|
||||||
class InMemoryActorSpec extends JUnitSuite {
|
class InMemoryActorSpec extends JUnitSuite {
|
||||||
@Test
|
@Test
|
||||||
def shouldOneWayMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
def shouldOneWayMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||||
val stateful = new InMemStatefulActor(2)
|
val stateful = newActor(() => new InMemStatefulActor(2))
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful ! SetMapStateOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init") // set init state
|
stateful ! SetMapStateOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init") // set init state
|
||||||
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
||||||
assert(stateful.notifier.await(1, TimeUnit.SECONDS))
|
val notifier: Option[CountDownLatch] = stateful !! GetNotifier
|
||||||
|
assert(notifier.get.await(1, TimeUnit.SECONDS))
|
||||||
assert("new state" === (stateful !! GetMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess")).get)
|
assert("new state" === (stateful !! GetMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess")).get)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
def shouldMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||||
val stateful = new InMemStatefulActor
|
val stateful = newActor[InMemStatefulActor]
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful !! SetMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init") // set init state
|
stateful !! SetMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init") // set init state
|
||||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
||||||
|
|
@ -124,22 +131,23 @@ class InMemoryActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldOneWayMapShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
def shouldOneWayMapShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||||
val stateful = new InMemStatefulActor(2)
|
val stateful = newActor(() => new InMemStatefulActor(2))
|
||||||
stateful.start
|
stateful.start
|
||||||
val failer = new InMemFailerActor
|
val failer = newActor[InMemFailerActor]
|
||||||
failer.start
|
failer.start
|
||||||
stateful ! SetMapStateOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init") // set init state
|
stateful ! SetMapStateOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init") // set init state
|
||||||
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
||||||
assert(stateful.notifier.await(1, TimeUnit.SECONDS))
|
val notifier: Option[CountDownLatch] = stateful !! GetNotifier
|
||||||
|
assert(notifier.get.await(1, TimeUnit.SECONDS))
|
||||||
assert("init" === (stateful !! GetMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure")).get) // check that state is == init state
|
assert("init" === (stateful !! GetMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure")).get) // check that state is == init state
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldMapShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
def shouldMapShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||||
val stateful = new InMemStatefulActor
|
val stateful = newActor[InMemStatefulActor]
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful !! SetMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init") // set init state
|
stateful !! SetMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init") // set init state
|
||||||
val failer = new InMemFailerActor
|
val failer = newActor[InMemFailerActor]
|
||||||
failer.start
|
failer.start
|
||||||
try {
|
try {
|
||||||
stateful !! Failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
stateful !! Failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
||||||
|
|
@ -150,17 +158,18 @@ class InMemoryActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldOneWayVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
def shouldOneWayVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||||
val stateful = new InMemStatefulActor(2)
|
val stateful = newActor(() => new InMemStatefulActor(2))
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful ! SetVectorStateOneWay("init") // set init state
|
stateful ! SetVectorStateOneWay("init") // set init state
|
||||||
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
||||||
assert(stateful.notifier.await(1, TimeUnit.SECONDS))
|
val notifier: Option[CountDownLatch] = stateful !! GetNotifier
|
||||||
|
assert(notifier.get.await(1, TimeUnit.SECONDS))
|
||||||
assert(2 === (stateful !! GetVectorSize).get)
|
assert(2 === (stateful !! GetVectorSize).get)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
def shouldVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||||
val stateful = new InMemStatefulActor
|
val stateful = newActor[InMemStatefulActor]
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful !! SetVectorState("init") // set init state
|
stateful !! SetVectorState("init") // set init state
|
||||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
||||||
|
|
@ -169,23 +178,24 @@ class InMemoryActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldOneWayVectorShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
def shouldOneWayVectorShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||||
val stateful = new InMemStatefulActor(2)
|
val stateful = newActor(() => new InMemStatefulActor(2))
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful ! SetVectorStateOneWay("init") // set init state
|
stateful ! SetVectorStateOneWay("init") // set init state
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
val failer = new InMemFailerActor
|
val failer = newActor[InMemFailerActor]
|
||||||
failer.start
|
failer.start
|
||||||
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
||||||
assert(stateful.notifier.await(1, TimeUnit.SECONDS))
|
val notifier: Option[CountDownLatch] = stateful !! GetNotifier
|
||||||
|
assert(notifier.get.await(1, TimeUnit.SECONDS))
|
||||||
assert(1 === (stateful !! GetVectorSize).get)
|
assert(1 === (stateful !! GetVectorSize).get)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldVectorShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
def shouldVectorShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||||
val stateful = new InMemStatefulActor
|
val stateful = newActor[InMemStatefulActor]
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful !! SetVectorState("init") // set init state
|
stateful !! SetVectorState("init") // set init state
|
||||||
val failer = new InMemFailerActor
|
val failer = newActor[InMemFailerActor]
|
||||||
failer.start
|
failer.start
|
||||||
try {
|
try {
|
||||||
stateful !! Failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
stateful !! Failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
||||||
|
|
@ -196,17 +206,18 @@ class InMemoryActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldOneWayRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
def shouldOneWayRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||||
val stateful = new InMemStatefulActor(2)
|
val stateful = newActor(() => new InMemStatefulActor(2))
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful ! SetRefStateOneWay("init") // set init state
|
stateful ! SetRefStateOneWay("init") // set init state
|
||||||
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
||||||
assert(stateful.notifier.await(1, TimeUnit.SECONDS))
|
val notifier: Option[CountDownLatch] = stateful !! GetNotifier
|
||||||
|
assert(notifier.get.await(1, TimeUnit.SECONDS))
|
||||||
assert("new state" === (stateful !! GetRefState).get)
|
assert("new state" === (stateful !! GetRefState).get)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
def shouldRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||||
val stateful = new InMemStatefulActor
|
val stateful = newActor[InMemStatefulActor]
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful !! SetRefState("init") // set init state
|
stateful !! SetRefState("init") // set init state
|
||||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactionrequired
|
||||||
|
|
@ -215,23 +226,24 @@ class InMemoryActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldOneWayRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
def shouldOneWayRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||||
val stateful = new InMemStatefulActor(2)
|
val stateful = newActor(() => new InMemStatefulActor(2))
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful ! SetRefStateOneWay("init") // set init state
|
stateful ! SetRefStateOneWay("init") // set init state
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
val failer = new InMemFailerActor
|
val failer = newActor[InMemFailerActor]
|
||||||
failer.start
|
failer.start
|
||||||
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
||||||
assert(stateful.notifier.await(1, TimeUnit.SECONDS))
|
val notifier: Option[CountDownLatch] = stateful !! GetNotifier
|
||||||
|
assert(notifier.get.await(1, TimeUnit.SECONDS))
|
||||||
assert("init" === (stateful !! (GetRefState, 1000000)).get) // check that state is == init state
|
assert("init" === (stateful !! (GetRefState, 1000000)).get) // check that state is == init state
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def shouldRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
def shouldRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||||
val stateful = new InMemStatefulActor
|
val stateful = newActor[InMemStatefulActor]
|
||||||
stateful.start
|
stateful.start
|
||||||
stateful !! SetRefState("init") // set init state
|
stateful !! SetRefState("init") // set init state
|
||||||
val failer = new InMemFailerActor
|
val failer = newActor[InMemFailerActor]
|
||||||
failer.start
|
failer.start
|
||||||
try {
|
try {
|
||||||
stateful !! Failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
stateful !! Failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactionrequired method
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package se.scalablesolutions.akka.actor
|
||||||
|
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class MemoryFootprintSpec extends JUnitSuite {
|
class MemoryFootprintSpec extends JUnitSuite {
|
||||||
class Mem extends Actor {
|
class Mem extends Actor {
|
||||||
|
|
|
||||||
|
|
@ -1,307 +0,0 @@
|
||||||
package se.scalablesolutions.akka
|
|
||||||
|
|
||||||
import org.scalatest.junit.JUnitSuite
|
|
||||||
import org.junit.Test
|
|
||||||
import net.lag.logging.Logger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Computer Language Benchmarks Game
|
|
||||||
* <p/>
|
|
||||||
* URL: [http://shootout.alioth.debian.org/]
|
|
||||||
* <p/>
|
|
||||||
* Contributed by Julien Gaugaz.
|
|
||||||
* <p/>
|
|
||||||
* Inspired by the version contributed by Yura Taras and modified by Isaac Gouy.
|
|
||||||
*/
|
|
||||||
class PerformanceSpec extends JUnitSuite {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
def dummyTest = assert(true)
|
|
||||||
|
|
||||||
// @Test
|
|
||||||
def benchAkkaActorsVsScalaActors = {
|
|
||||||
|
|
||||||
def stressTestAkkaActors(nrOfMessages: Int, nrOfActors: Int, sleepTime: Int): Long = {
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
|
||||||
|
|
||||||
abstract class Colour
|
|
||||||
case object RED extends Colour
|
|
||||||
case object YELLOW extends Colour
|
|
||||||
case object BLUE extends Colour
|
|
||||||
case object FADED extends Colour
|
|
||||||
|
|
||||||
val colours = Array[Colour](BLUE, RED, YELLOW)
|
|
||||||
|
|
||||||
case class Meet(from: Actor, colour: Colour)
|
|
||||||
case class Change(colour: Colour)
|
|
||||||
case class MeetingCount(count: Int)
|
|
||||||
case class ExitActor(actor: Actor, reason: String)
|
|
||||||
|
|
||||||
var totalTime = 0L
|
|
||||||
|
|
||||||
class Mall(var nrMeets: Int, numChameneos: Int) extends Actor {
|
|
||||||
var waitingChameneo: Option[Actor] = None
|
|
||||||
var sumMeetings = 0
|
|
||||||
var numFaded = 0
|
|
||||||
var startTime: Long = 0L
|
|
||||||
|
|
||||||
start
|
|
||||||
|
|
||||||
def startChameneos(): Unit = {
|
|
||||||
startTime = System.currentTimeMillis
|
|
||||||
var i = 0
|
|
||||||
while (i < numChameneos) {
|
|
||||||
Chameneo(this, colours(i % 3), i).start
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def sender : Option[Actor] = replyTo match {
|
|
||||||
case Some(Left(actor)) => Some(actor)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
def receive = {
|
|
||||||
case MeetingCount(i) => {
|
|
||||||
numFaded = numFaded + 1
|
|
||||||
sumMeetings = sumMeetings + i
|
|
||||||
if (numFaded == numChameneos) {
|
|
||||||
totalTime = System.currentTimeMillis - startTime
|
|
||||||
println("time: " + totalTime)
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case msg@Meet(a, c) => {
|
|
||||||
if (nrMeets > 0) {
|
|
||||||
waitingChameneo match {
|
|
||||||
case Some(chameneo) =>
|
|
||||||
nrMeets = nrMeets - 1
|
|
||||||
chameneo ! msg
|
|
||||||
waitingChameneo = None
|
|
||||||
case None =>
|
|
||||||
waitingChameneo = sender
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingChameneo match {
|
|
||||||
case Some(chameneo) =>
|
|
||||||
chameneo ! ExitActor(this, "normal")
|
|
||||||
case None =>
|
|
||||||
}
|
|
||||||
sender.get ! ExitActor(this, "normal")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class Chameneo(var mall: Mall, var colour: Colour, cid: Int) extends Actor {
|
|
||||||
var meetings = 0
|
|
||||||
|
|
||||||
override def start = {
|
|
||||||
val r = super.start
|
|
||||||
mall ! Meet(this, colour)
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def sender : Option[Actor] = replyTo match {
|
|
||||||
case Some(Left(actor)) => Some(actor)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
override def receive: PartialFunction[Any, Unit] = {
|
|
||||||
case Meet(from, otherColour) =>
|
|
||||||
colour = complement(otherColour)
|
|
||||||
meetings = meetings + 1
|
|
||||||
from ! Change(colour)
|
|
||||||
mall ! Meet(this, colour)
|
|
||||||
case Change(newColour) =>
|
|
||||||
colour = newColour
|
|
||||||
meetings = meetings + 1
|
|
||||||
mall ! Meet(this, colour)
|
|
||||||
case ExitActor(_, _) =>
|
|
||||||
colour = FADED
|
|
||||||
sender.get ! MeetingCount(meetings)
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
def complement(otherColour: Colour): Colour = {
|
|
||||||
colour match {
|
|
||||||
case RED => otherColour match {
|
|
||||||
case RED => RED
|
|
||||||
case YELLOW => BLUE
|
|
||||||
case BLUE => YELLOW
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
case YELLOW => otherColour match {
|
|
||||||
case RED => BLUE
|
|
||||||
case YELLOW => YELLOW
|
|
||||||
case BLUE => RED
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
case BLUE => otherColour match {
|
|
||||||
case RED => YELLOW
|
|
||||||
case YELLOW => RED
|
|
||||||
case BLUE => BLUE
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def toString() = cid + "(" + colour + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
val mall = new Mall(nrOfMessages, nrOfActors)
|
|
||||||
mall.startChameneos
|
|
||||||
Thread.sleep(sleepTime)
|
|
||||||
totalTime
|
|
||||||
}
|
|
||||||
|
|
||||||
def stressTestScalaActors(nrOfMessages: Int, nrOfActors: Int, sleepTime: Int): Long = {
|
|
||||||
var totalTime = 0L
|
|
||||||
|
|
||||||
import scala.actors._
|
|
||||||
import scala.actors.Actor._
|
|
||||||
|
|
||||||
abstract class Colour
|
|
||||||
case object RED extends Colour
|
|
||||||
case object YELLOW extends Colour
|
|
||||||
case object BLUE extends Colour
|
|
||||||
case object FADED extends Colour
|
|
||||||
|
|
||||||
val colours = Array[Colour](BLUE, RED, YELLOW)
|
|
||||||
|
|
||||||
case class Meet(colour: Colour)
|
|
||||||
case class Change(colour: Colour)
|
|
||||||
case class MeetingCount(count: Int)
|
|
||||||
|
|
||||||
|
|
||||||
class Mall(var n: Int, numChameneos: Int) extends Actor {
|
|
||||||
var waitingChameneo: Option[OutputChannel[Any]] = None
|
|
||||||
var startTime: Long = 0L
|
|
||||||
|
|
||||||
start()
|
|
||||||
|
|
||||||
def startChameneos(): Unit = {
|
|
||||||
startTime = System.currentTimeMillis
|
|
||||||
var i = 0
|
|
||||||
while (i < numChameneos) {
|
|
||||||
Chameneo(this, colours(i % 3), i).start()
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def act() {
|
|
||||||
var sumMeetings = 0
|
|
||||||
var numFaded = 0
|
|
||||||
loop {
|
|
||||||
react {
|
|
||||||
|
|
||||||
case MeetingCount(i) => {
|
|
||||||
numFaded = numFaded + 1
|
|
||||||
sumMeetings = sumMeetings + i
|
|
||||||
if (numFaded == numChameneos) {
|
|
||||||
totalTime = System.currentTimeMillis - startTime
|
|
||||||
exit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case msg@Meet(c) => {
|
|
||||||
if (n > 0) {
|
|
||||||
waitingChameneo match {
|
|
||||||
case Some(chameneo) =>
|
|
||||||
n = n - 1
|
|
||||||
chameneo.forward(msg)
|
|
||||||
waitingChameneo = None
|
|
||||||
case None =>
|
|
||||||
waitingChameneo = Some(sender)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingChameneo match {
|
|
||||||
case Some(chameneo) =>
|
|
||||||
chameneo ! Exit(this, "normal")
|
|
||||||
case None =>
|
|
||||||
}
|
|
||||||
sender ! Exit(this, "normal")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class Chameneo(var mall: Mall, var colour: Colour, id: Int) extends Actor {
|
|
||||||
var meetings = 0
|
|
||||||
|
|
||||||
def act() {
|
|
||||||
loop {
|
|
||||||
mall ! Meet(colour)
|
|
||||||
react {
|
|
||||||
case Meet(otherColour) =>
|
|
||||||
colour = complement(otherColour)
|
|
||||||
meetings = meetings + 1
|
|
||||||
sender ! Change(colour)
|
|
||||||
case Change(newColour) =>
|
|
||||||
colour = newColour
|
|
||||||
meetings = meetings + 1
|
|
||||||
case Exit(_, _) =>
|
|
||||||
colour = FADED
|
|
||||||
sender ! MeetingCount(meetings)
|
|
||||||
exit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def complement(otherColour: Colour): Colour = {
|
|
||||||
colour match {
|
|
||||||
case RED => otherColour match {
|
|
||||||
case RED => RED
|
|
||||||
case YELLOW => BLUE
|
|
||||||
case BLUE => YELLOW
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
case YELLOW => otherColour match {
|
|
||||||
case RED => BLUE
|
|
||||||
case YELLOW => YELLOW
|
|
||||||
case BLUE => RED
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
case BLUE => otherColour match {
|
|
||||||
case RED => YELLOW
|
|
||||||
case YELLOW => RED
|
|
||||||
case BLUE => BLUE
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
case FADED => FADED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def toString() = id + "(" + colour + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
val mall = new Mall(nrOfMessages, nrOfActors)
|
|
||||||
mall.startChameneos
|
|
||||||
Thread.sleep(sleepTime)
|
|
||||||
totalTime
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.INFO
|
|
||||||
println("===========================================")
|
|
||||||
println("== Benchmark Akka Actors vs Scala Actors ==")
|
|
||||||
|
|
||||||
var nrOfMessages = 2000000
|
|
||||||
var nrOfActors = 4
|
|
||||||
var akkaTime = stressTestAkkaActors(nrOfMessages, nrOfActors, 1000 * 30)
|
|
||||||
var scalaTime = stressTestScalaActors(nrOfMessages, nrOfActors, 1000 * 40)
|
|
||||||
var ratio: Double = scalaTime.toDouble / akkaTime.toDouble
|
|
||||||
|
|
||||||
println("\tNr of messages:\t" + nrOfMessages)
|
|
||||||
println("\tNr of actors:\t" + nrOfActors)
|
|
||||||
println("\tAkka Actors:\t" + akkaTime + "\t milliseconds")
|
|
||||||
println("\tScala Actors:\t" + scalaTime + "\t milliseconds")
|
|
||||||
println("\tAkka is " + ratio + " times faster\n")
|
|
||||||
println("===========================================")
|
|
||||||
assert(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,11 +3,11 @@ package se.scalablesolutions.akka.actor
|
||||||
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import Actor._
|
||||||
|
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
|
||||||
class ReactorBasedSingleThreadEventDrivenDispatcherActorSpec extends JUnitSuite {
|
class ReactorBasedSingleThreadEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
import Actor.Sender.Self
|
|
||||||
|
|
||||||
private val unit = TimeUnit.MILLISECONDS
|
private val unit = TimeUnit.MILLISECONDS
|
||||||
|
|
||||||
|
|
@ -22,22 +22,26 @@ class ReactorBasedSingleThreadEventDrivenDispatcherActorSpec extends JUnitSuite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendOneWay = {
|
object OneWayTestActor {
|
||||||
val oneWay = new CountDownLatch(1)
|
val oneWay = new CountDownLatch(1)
|
||||||
val actor = new Actor {
|
}
|
||||||
dispatcher = Dispatchers.newReactorBasedSingleThreadEventDrivenDispatcher(uuid)
|
class OneWayTestActor extends Actor {
|
||||||
def receive = {
|
dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher(uuid)
|
||||||
case "OneWay" => oneWay.countDown
|
def receive = {
|
||||||
}
|
case "OneWay" => OneWayTestActor.oneWay.countDown
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test def shouldSendOneWay = {
|
||||||
|
val actor = newActor[OneWayTestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor ! "OneWay"
|
val result = actor ! "OneWay"
|
||||||
assert(oneWay.await(1, TimeUnit.SECONDS))
|
assert(OneWayTestActor.oneWay.await(1, TimeUnit.SECONDS))
|
||||||
actor.stop
|
actor.stop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplySync = {
|
@Test def shouldSendReplySync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result: String = (actor !! ("Hello", 10000)).get
|
val result: String = (actor !! ("Hello", 10000)).get
|
||||||
assert("World" === result)
|
assert("World" === result)
|
||||||
|
|
@ -45,7 +49,7 @@ class ReactorBasedSingleThreadEventDrivenDispatcherActorSpec extends JUnitSuite
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplyAsync = {
|
@Test def shouldSendReplyAsync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor !! "Hello"
|
val result = actor !! "Hello"
|
||||||
assert("World" === result.get.asInstanceOf[String])
|
assert("World" === result.get.asInstanceOf[String])
|
||||||
|
|
@ -53,7 +57,7 @@ class ReactorBasedSingleThreadEventDrivenDispatcherActorSpec extends JUnitSuite
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReceiveException = {
|
@Test def shouldSendReceiveException = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
try {
|
try {
|
||||||
actor !! "Failure"
|
actor !! "Failure"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ package se.scalablesolutions.akka.actor
|
||||||
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ReactorBasedThreadPoolEventDrivenDispatcherActorSpec extends JUnitSuite {
|
class ReactorBasedThreadPoolEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
import Actor.Sender.Self
|
import Actor.Sender.Self
|
||||||
|
|
@ -22,12 +24,12 @@ class ReactorBasedThreadPoolEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test def shouldSendOneWay = {
|
@Test def shouldSendOneWay = {
|
||||||
val oneWay = new CountDownLatch(1)
|
val oneWay = new CountDownLatch(1)
|
||||||
val actor = new Actor {
|
val actor = newActor(() => new Actor {
|
||||||
dispatcher = Dispatchers.newReactorBasedThreadPoolEventDrivenDispatcher(uuid)
|
dispatcher = Dispatchers.newReactorBasedThreadPoolEventDrivenDispatcher(uuid)
|
||||||
def receive = {
|
def receive = {
|
||||||
case "OneWay" => oneWay.countDown
|
case "OneWay" => oneWay.countDown
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor ! "OneWay"
|
val result = actor ! "OneWay"
|
||||||
assert(oneWay.await(1, TimeUnit.SECONDS))
|
assert(oneWay.await(1, TimeUnit.SECONDS))
|
||||||
|
|
@ -35,7 +37,7 @@ class ReactorBasedThreadPoolEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplySync = {
|
@Test def shouldSendReplySync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result: String = (actor !! ("Hello", 10000)).get
|
val result: String = (actor !! ("Hello", 10000)).get
|
||||||
assert("World" === result)
|
assert("World" === result)
|
||||||
|
|
@ -43,7 +45,7 @@ class ReactorBasedThreadPoolEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplyAsync = {
|
@Test def shouldSendReplyAsync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor !! "Hello"
|
val result = actor !! "Hello"
|
||||||
assert("World" === result.get.asInstanceOf[String])
|
assert("World" === result.get.asInstanceOf[String])
|
||||||
|
|
@ -51,7 +53,7 @@ class ReactorBasedThreadPoolEventDrivenDispatcherActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReceiveException = {
|
@Test def shouldSendReceiveException = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
try {
|
try {
|
||||||
actor !! "Failure"
|
actor !! "Failure"
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
package se.scalablesolutions.akka.actor
|
|
||||||
|
|
||||||
import se.scalablesolutions.akka.remote.RemoteNode
|
|
||||||
import se.scalablesolutions.akka.actor._
|
|
||||||
import Actor.Sender.Self
|
|
||||||
|
|
||||||
import org.scalatest.junit.JUnitSuite
|
|
||||||
import org.junit.Test
|
|
||||||
/*
|
|
||||||
class RemoteClientShutdownTest extends JUnitSuite {
|
|
||||||
@Test def shouldShutdownRemoteClient = {
|
|
||||||
RemoteNode.start("localhost", 9999)
|
|
||||||
|
|
||||||
var remote = new TravelingActor
|
|
||||||
remote.start
|
|
||||||
remote ! "sending a remote message"
|
|
||||||
remote.stop
|
|
||||||
|
|
||||||
Thread.sleep(1000)
|
|
||||||
RemoteNode.shutdown
|
|
||||||
println("======= REMOTE CLIENT SHUT DOWN FINE =======")
|
|
||||||
assert(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TravelingActor extends RemoteActor("localhost", 9999) {
|
|
||||||
def receive = {
|
|
||||||
case _ => log.info("message received")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -4,12 +4,13 @@
|
||||||
|
|
||||||
package se.scalablesolutions.akka.actor
|
package se.scalablesolutions.akka.actor
|
||||||
|
|
||||||
import _root_.java.util.concurrent.{LinkedBlockingQueue, TimeUnit, BlockingQueue}
|
import java.util.concurrent.{LinkedBlockingQueue, TimeUnit, BlockingQueue}
|
||||||
import se.scalablesolutions.akka.serialization.BinaryString
|
import se.scalablesolutions.akka.serialization.BinaryString
|
||||||
import se.scalablesolutions.akka.config.ScalaConfig._
|
import se.scalablesolutions.akka.config.ScalaConfig._
|
||||||
import se.scalablesolutions.akka.remote.{RemoteNode, RemoteServer}
|
import se.scalablesolutions.akka.remote.{RemoteNode, RemoteServer}
|
||||||
import se.scalablesolutions.akka.OneWay
|
import se.scalablesolutions.akka.OneWay
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -82,9 +83,9 @@ class RemoteSupervisorSpec extends JUnitSuite {
|
||||||
}).start
|
}).start
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
|
|
||||||
var pingpong1: RemotePingPong1Actor = _
|
var pingpong1: ActorID = _
|
||||||
var pingpong2: RemotePingPong2Actor = _
|
var pingpong2: ActorID = _
|
||||||
var pingpong3: RemotePingPong3Actor = _
|
var pingpong3: ActorID = _
|
||||||
|
|
||||||
@Test def shouldStartServer = {
|
@Test def shouldStartServer = {
|
||||||
Log.messageLog.clear
|
Log.messageLog.clear
|
||||||
|
|
@ -334,7 +335,7 @@ class RemoteSupervisorSpec extends JUnitSuite {
|
||||||
// Then create a concrete container in which we mix in support for the specific
|
// Then create a concrete container in which we mix in support for the specific
|
||||||
// implementation of the Actors we want to use.
|
// implementation of the Actors we want to use.
|
||||||
|
|
||||||
pingpong1 = new RemotePingPong1Actor
|
pingpong1 = newActor[RemotePingPong1Actor]
|
||||||
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
|
|
@ -349,7 +350,7 @@ class RemoteSupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getSingleActorOneForOneSupervisor: Supervisor = {
|
def getSingleActorOneForOneSupervisor: Supervisor = {
|
||||||
pingpong1 = new RemotePingPong1Actor
|
pingpong1 = newActor[RemotePingPong1Actor]
|
||||||
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
|
|
@ -363,11 +364,11 @@ class RemoteSupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getMultipleActorsAllForOneConf: Supervisor = {
|
def getMultipleActorsAllForOneConf: Supervisor = {
|
||||||
pingpong1 = new RemotePingPong1Actor
|
pingpong1 = newActor[RemotePingPong1Actor]
|
||||||
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
pingpong2 = new RemotePingPong2Actor
|
pingpong2 = newActor[RemotePingPong2Actor]
|
||||||
pingpong2.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong2.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
pingpong3 = new RemotePingPong3Actor
|
pingpong3 = newActor[RemotePingPong3Actor]
|
||||||
pingpong3.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong3.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
|
|
@ -389,11 +390,11 @@ class RemoteSupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getMultipleActorsOneForOneConf: Supervisor = {
|
def getMultipleActorsOneForOneConf: Supervisor = {
|
||||||
pingpong1 = new RemotePingPong1Actor
|
pingpong1 = newActor[RemotePingPong1Actor]
|
||||||
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
pingpong2 = new RemotePingPong2Actor
|
pingpong2 = newActor[RemotePingPong2Actor]
|
||||||
pingpong2.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong2.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
pingpong3 = new RemotePingPong3Actor
|
pingpong3 = newActor[RemotePingPong3Actor]
|
||||||
pingpong3.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong3.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
|
|
@ -415,11 +416,11 @@ class RemoteSupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getNestedSupervisorsAllForOneConf: Supervisor = {
|
def getNestedSupervisorsAllForOneConf: Supervisor = {
|
||||||
pingpong1 = new RemotePingPong1Actor
|
pingpong1 = newActor[RemotePingPong1Actor]
|
||||||
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong1.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
pingpong2 = new RemotePingPong2Actor
|
pingpong2 = newActor[RemotePingPong2Actor]
|
||||||
pingpong2.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong2.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
pingpong3 = new RemotePingPong3Actor
|
pingpong3 = newActor[RemotePingPong3Actor]
|
||||||
pingpong3.makeRemote(RemoteServer.HOSTNAME, 9988)
|
pingpong3.makeRemote(RemoteServer.HOSTNAME, 9988)
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.util.concurrent.TimeUnit
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class SchedulerSpec extends JUnitSuite {
|
class SchedulerSpec extends JUnitSuite {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import se.scalablesolutions.akka.actor.Actor
|
||||||
import se.scalablesolutions.akka.remote.{RemoteClient, RemoteNode}
|
import se.scalablesolutions.akka.remote.{RemoteClient, RemoteNode}
|
||||||
import se.scalablesolutions.akka.util.Logging
|
import se.scalablesolutions.akka.util.Logging
|
||||||
|
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class HelloWorldActor extends Actor {
|
class HelloWorldActor extends Actor {
|
||||||
start
|
start
|
||||||
def receive = {
|
def receive = {
|
||||||
|
|
@ -15,7 +17,7 @@ object ServerInitiatedRemoteActorServer {
|
||||||
|
|
||||||
def run = {
|
def run = {
|
||||||
RemoteNode.start("localhost", 9999)
|
RemoteNode.start("localhost", 9999)
|
||||||
RemoteNode.register("hello-service", new HelloWorldActor)
|
RemoteNode.register("hello-service", newActor[HelloWorldActor])
|
||||||
}
|
}
|
||||||
|
|
||||||
def main(args: Array[String]) = run
|
def main(args: Array[String]) = run
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.{Test, Before, After}
|
import org.junit.{Test, Before, After}
|
||||||
|
|
||||||
|
import Actor._
|
||||||
import se.scalablesolutions.akka.remote.{RemoteServer, RemoteClient}
|
import se.scalablesolutions.akka.remote.{RemoteServer, RemoteClient}
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
|
||||||
|
|
@ -12,7 +13,7 @@ object ServerInitiatedRemoteActorSpec {
|
||||||
val PORT = 9990
|
val PORT = 9990
|
||||||
var server: RemoteServer = null
|
var server: RemoteServer = null
|
||||||
|
|
||||||
case class Send(actor: Actor)
|
case class Send(actor: ActorID)
|
||||||
|
|
||||||
object RemoteActorSpecActorUnidirectional {
|
object RemoteActorSpecActorUnidirectional {
|
||||||
val latch = new CountDownLatch(1)
|
val latch = new CountDownLatch(1)
|
||||||
|
|
@ -42,23 +43,21 @@ object ServerInitiatedRemoteActorSpec {
|
||||||
class RemoteActorSpecActorAsyncSender extends Actor {
|
class RemoteActorSpecActorAsyncSender extends Actor {
|
||||||
start
|
start
|
||||||
def receive = {
|
def receive = {
|
||||||
case Send(actor: Actor) =>
|
case Send(actor: ActorID) =>
|
||||||
actor ! "Hello"
|
actor ! "Hello"
|
||||||
case "World" =>
|
case "World" =>
|
||||||
RemoteActorSpecActorAsyncSender.latch.countDown
|
RemoteActorSpecActorAsyncSender.latch.countDown
|
||||||
}
|
}
|
||||||
|
|
||||||
def send(actor: Actor) {
|
def send(actor: ActorID) {
|
||||||
this ! Send(actor)
|
self ! Send(actor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServerInitiatedRemoteActorSpec extends JUnitSuite {
|
class ServerInitiatedRemoteActorSpec extends JUnitSuite {
|
||||||
import ServerInitiatedRemoteActorSpec._
|
import ServerInitiatedRemoteActorSpec._
|
||||||
|
import se.scalablesolutions.akka.config.Config.config
|
||||||
import Actor.Sender.Self
|
|
||||||
se.scalablesolutions.akka.config.Config.config
|
|
||||||
|
|
||||||
private val unit = TimeUnit.MILLISECONDS
|
private val unit = TimeUnit.MILLISECONDS
|
||||||
|
|
||||||
|
|
@ -68,9 +67,9 @@ class ServerInitiatedRemoteActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
server.start(HOSTNAME, PORT)
|
server.start(HOSTNAME, PORT)
|
||||||
|
|
||||||
server.register(new RemoteActorSpecActorUnidirectional)
|
server.register(newActor[RemoteActorSpecActorUnidirectional])
|
||||||
server.register(new RemoteActorSpecActorBidirectional)
|
server.register(newActor[RemoteActorSpecActorBidirectional])
|
||||||
server.register(new RemoteActorSpecActorAsyncSender)
|
server.register(newActor[RemoteActorSpecActorAsyncSender])
|
||||||
|
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package se.scalablesolutions.akka.remote
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.Actor
|
||||||
|
|
||||||
|
import Actor._
|
||||||
|
|
||||||
object ActorShutdownRunner {
|
object ActorShutdownRunner {
|
||||||
def main(args: Array[String]) {
|
def main(args: Array[String]) {
|
||||||
class MyActor extends Actor {
|
class MyActor extends Actor {
|
||||||
|
|
@ -11,7 +13,7 @@ object ActorShutdownRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val myActor = new MyActor
|
val myActor = newActor[MyActor]
|
||||||
myActor.start
|
myActor.start
|
||||||
myActor ! "test"
|
myActor ! "test"
|
||||||
myActor.stop
|
myActor.stop
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package se.scalablesolutions.akka.actor
|
||||||
|
|
||||||
import se.scalablesolutions.akka.stm._
|
import se.scalablesolutions.akka.stm._
|
||||||
|
|
||||||
|
import Actor._
|
||||||
|
|
||||||
import org.scalatest.Spec
|
import org.scalatest.Spec
|
||||||
import org.scalatest.Assertions
|
import org.scalatest.Assertions
|
||||||
import org.scalatest.matchers.ShouldMatchers
|
import org.scalatest.matchers.ShouldMatchers
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@
|
||||||
|
|
||||||
package se.scalablesolutions.akka.actor
|
package se.scalablesolutions.akka.actor
|
||||||
|
|
||||||
import _root_.java.util.concurrent.{TimeUnit, BlockingQueue, LinkedBlockingQueue}
|
import java.util.concurrent.{TimeUnit, BlockingQueue, LinkedBlockingQueue}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.config.ScalaConfig._
|
import se.scalablesolutions.akka.config.ScalaConfig._
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
import se.scalablesolutions.akka.{OneWay, Die, Ping}
|
import se.scalablesolutions.akka.{OneWay, Die, Ping}
|
||||||
|
import Actor._
|
||||||
|
|
||||||
import org.scalatest.junit.JUnitSuite
|
import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -20,9 +22,9 @@ class SupervisorSpec extends JUnitSuite {
|
||||||
var messageLog: BlockingQueue[String] = new LinkedBlockingQueue[String]
|
var messageLog: BlockingQueue[String] = new LinkedBlockingQueue[String]
|
||||||
var oneWayLog: BlockingQueue[String] = new LinkedBlockingQueue[String]
|
var oneWayLog: BlockingQueue[String] = new LinkedBlockingQueue[String]
|
||||||
|
|
||||||
var pingpong1: PingPong1Actor = _
|
var pingpong1: ActorID = _
|
||||||
var pingpong2: PingPong2Actor = _
|
var pingpong2: ActorID = _
|
||||||
var pingpong3: PingPong3Actor = _
|
var pingpong3: ActorID = _
|
||||||
|
|
||||||
@Test def shouldStartServer = {
|
@Test def shouldStartServer = {
|
||||||
messageLog.clear
|
messageLog.clear
|
||||||
|
|
@ -370,7 +372,7 @@ class SupervisorSpec extends JUnitSuite {
|
||||||
// Creat some supervisors with different configurations
|
// Creat some supervisors with different configurations
|
||||||
|
|
||||||
def getSingleActorAllForOneSupervisor: Supervisor = {
|
def getSingleActorAllForOneSupervisor: Supervisor = {
|
||||||
pingpong1 = new PingPong1Actor
|
pingpong1 = newActor[PingPong1Actor]
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
SupervisorConfig(
|
SupervisorConfig(
|
||||||
|
|
@ -383,7 +385,7 @@ class SupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getSingleActorOneForOneSupervisor: Supervisor = {
|
def getSingleActorOneForOneSupervisor: Supervisor = {
|
||||||
pingpong1 = new PingPong1Actor
|
pingpong1 = newActor[PingPong1Actor]
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
SupervisorConfig(
|
SupervisorConfig(
|
||||||
|
|
@ -396,9 +398,9 @@ class SupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getMultipleActorsAllForOneConf: Supervisor = {
|
def getMultipleActorsAllForOneConf: Supervisor = {
|
||||||
pingpong1 = new PingPong1Actor
|
pingpong1 = newActor[PingPong1Actor]
|
||||||
pingpong2 = new PingPong2Actor
|
pingpong2 = newActor[PingPong2Actor]
|
||||||
pingpong3 = new PingPong3Actor
|
pingpong3 = newActor[PingPong3Actor]
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
SupervisorConfig(
|
SupervisorConfig(
|
||||||
|
|
@ -419,9 +421,9 @@ class SupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getMultipleActorsOneForOneConf: Supervisor = {
|
def getMultipleActorsOneForOneConf: Supervisor = {
|
||||||
pingpong1 = new PingPong1Actor
|
pingpong1 = newActor[PingPong1Actor]
|
||||||
pingpong2 = new PingPong2Actor
|
pingpong2 = newActor[PingPong2Actor]
|
||||||
pingpong3 = new PingPong3Actor
|
pingpong3 = newActor[PingPong3Actor]
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
SupervisorConfig(
|
SupervisorConfig(
|
||||||
|
|
@ -442,9 +444,9 @@ class SupervisorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
def getNestedSupervisorsAllForOneConf: Supervisor = {
|
def getNestedSupervisorsAllForOneConf: Supervisor = {
|
||||||
pingpong1 = new PingPong1Actor
|
pingpong1 = newActor[PingPong1Actor]
|
||||||
pingpong2 = new PingPong2Actor
|
pingpong2 = newActor[PingPong2Actor]
|
||||||
pingpong3 = new PingPong3Actor
|
pingpong3 = newActor[PingPong3Actor]
|
||||||
|
|
||||||
val factory = SupervisorFactory(
|
val factory = SupervisorFactory(
|
||||||
SupervisorConfig(
|
SupervisorConfig(
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package se.scalablesolutions.akka.actor
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actor which can be used as the basis for unit testing actors. I automatically start and stops all involved handlers before and after
|
|
||||||
* the test.
|
|
||||||
*/
|
|
||||||
abstract class TestActor extends Actor with ActorTestUtil {
|
|
||||||
def test: Unit
|
|
||||||
def receive = {case _ =>}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ActorTestUtil {
|
|
||||||
def handle[T](actors: Actor*)(test: => T): T = {
|
|
||||||
for (a <- actors) a.start
|
|
||||||
try {
|
|
||||||
test
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
for (a <- actors) a.stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def verify(actor: TestActor): Unit = handle(actor) {
|
|
||||||
actor.test
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import se.scalablesolutions.akka.dispatch.Dispatchers
|
import se.scalablesolutions.akka.dispatch.Dispatchers
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ThreadBasedActorSpec extends JUnitSuite {
|
class ThreadBasedActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
|
|
@ -23,12 +24,12 @@ class ThreadBasedActorSpec extends JUnitSuite {
|
||||||
|
|
||||||
@Test def shouldSendOneWay = {
|
@Test def shouldSendOneWay = {
|
||||||
var oneWay = new CountDownLatch(1)
|
var oneWay = new CountDownLatch(1)
|
||||||
val actor = new Actor {
|
val actor = newActor(() => new Actor {
|
||||||
dispatcher = Dispatchers.newThreadBasedDispatcher(this)
|
dispatcher = Dispatchers.newThreadBasedDispatcher(this)
|
||||||
def receive = {
|
def receive = {
|
||||||
case "OneWay" => oneWay.countDown
|
case "OneWay" => oneWay.countDown
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor ! "OneWay"
|
val result = actor ! "OneWay"
|
||||||
assert(oneWay.await(1, TimeUnit.SECONDS))
|
assert(oneWay.await(1, TimeUnit.SECONDS))
|
||||||
|
|
@ -36,7 +37,7 @@ class ThreadBasedActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplySync = {
|
@Test def shouldSendReplySync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result: String = (actor !! ("Hello", 10000)).get
|
val result: String = (actor !! ("Hello", 10000)).get
|
||||||
assert("World" === result)
|
assert("World" === result)
|
||||||
|
|
@ -44,7 +45,7 @@ class ThreadBasedActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReplyAsync = {
|
@Test def shouldSendReplyAsync = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
val result = actor !! "Hello"
|
val result = actor !! "Hello"
|
||||||
assert("World" === result.get.asInstanceOf[String])
|
assert("World" === result.get.asInstanceOf[String])
|
||||||
|
|
@ -52,7 +53,7 @@ class ThreadBasedActorSpec extends JUnitSuite {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test def shouldSendReceiveException = {
|
@Test def shouldSendReceiveException = {
|
||||||
val actor = new TestActor
|
val actor = newActor[TestActor]
|
||||||
actor.start
|
actor.start
|
||||||
try {
|
try {
|
||||||
actor !! "Failure"
|
actor !! "Failure"
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ import org.scalatest.junit.JUnitSuite
|
||||||
import org.junit.{Test, Before}
|
import org.junit.{Test, Before}
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.Actor
|
import se.scalablesolutions.akka.actor.Actor
|
||||||
|
import Actor._
|
||||||
|
|
||||||
class ThreadBasedDispatcherSpec extends JUnitSuite {
|
class ThreadBasedDispatcherSpec extends JUnitSuite {
|
||||||
private var threadingIssueDetected: AtomicBoolean = null
|
private var threadingIssueDetected: AtomicBoolean = null
|
||||||
val key1 = new Actor { def receive = { case _ => {}} }
|
val key1 = newActor(() => new Actor { def receive = { case _ => {}} })
|
||||||
val key2 = new Actor { def receive = { case _ => {}} }
|
val key2 = newActor(() => new Actor { def receive = { case _ => {}} })
|
||||||
val key3 = new Actor { def receive = { case _ => {}} }
|
val key3 = newActor(() => new Actor { def receive = { case _ => {}} })
|
||||||
|
|
||||||
class TestMessageHandle(handleLatch: CountDownLatch) extends MessageInvoker {
|
class TestMessageHandle(handleLatch: CountDownLatch) extends MessageInvoker {
|
||||||
val guardLock: Lock = new ReentrantLock
|
val guardLock: Lock = new ReentrantLock
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import org.scalatest.matchers.ShouldMatchers
|
||||||
import org.scalatest.junit.JUnitRunner
|
import org.scalatest.junit.JUnitRunner
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import se.scalablesolutions.akka.actor.Actor._
|
||||||
|
|
||||||
@RunWith(classOf[JUnitRunner])
|
@RunWith(classOf[JUnitRunner])
|
||||||
class TransactionalRefSpec extends Spec with ShouldMatchers {
|
class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
|
|
||||||
|
|
@ -37,7 +39,7 @@ class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
val ref = Ref(0)
|
val ref = Ref(0)
|
||||||
|
|
||||||
def increment = atomic {
|
def increment = atomic {
|
||||||
ref alter (_ + 1)
|
ref alter (_ + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
increment
|
increment
|
||||||
|
|
@ -53,7 +55,7 @@ class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
val ref = Ref[Int]
|
val ref = Ref[Int]
|
||||||
|
|
||||||
def increment = atomic {
|
def increment = atomic {
|
||||||
ref alter (_ + 1)
|
ref alter (_ + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluating { increment } should produce [RuntimeException]
|
evaluating { increment } should produce [RuntimeException]
|
||||||
|
|
@ -63,7 +65,7 @@ class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
val ref1 = Ref(1)
|
val ref1 = Ref(1)
|
||||||
|
|
||||||
val ref2 = atomic {
|
val ref2 = atomic {
|
||||||
ref1 map (_ + 1)
|
ref1 map (_ + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val value1 = atomic { ref1.get.get }
|
val value1 = atomic { ref1.get.get }
|
||||||
|
|
@ -91,7 +93,7 @@ class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
val ref1 = Ref(1)
|
val ref1 = Ref(1)
|
||||||
|
|
||||||
val ref2 = atomic {
|
val ref2 = atomic {
|
||||||
for (value <- ref1) yield value + 2
|
for (value <- ref1) yield value + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
val value2 = atomic { ref2.get.get }
|
val value2 = atomic { ref2.get.get }
|
||||||
|
|
@ -104,10 +106,10 @@ class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
val ref2 = Ref(2)
|
val ref2 = Ref(2)
|
||||||
|
|
||||||
val ref3 = atomic {
|
val ref3 = atomic {
|
||||||
for {
|
for {
|
||||||
value1 <- ref1
|
value1 <- ref1
|
||||||
value2 <- ref2
|
value2 <- ref2
|
||||||
} yield value1 + value2
|
} yield value1 + value2
|
||||||
}
|
}
|
||||||
|
|
||||||
val value3 = atomic { ref3.get.get }
|
val value3 = atomic { ref3.get.get }
|
||||||
|
|
@ -119,13 +121,13 @@ class TransactionalRefSpec extends Spec with ShouldMatchers {
|
||||||
val ref1 = Ref(1)
|
val ref1 = Ref(1)
|
||||||
|
|
||||||
val refLess2 = atomic {
|
val refLess2 = atomic {
|
||||||
for (value <- ref1 if value < 2) yield value
|
for (value <- ref1 if value < 2) yield value
|
||||||
}
|
}
|
||||||
|
|
||||||
val optLess2 = atomic { refLess2.get }
|
val optLess2 = atomic { refLess2.get }
|
||||||
|
|
||||||
val refGreater2 = atomic {
|
val refGreater2 = atomic {
|
||||||
for (value <- ref1 if value > 2) yield value
|
for (value <- ref1 if value > 2) yield value
|
||||||
}
|
}
|
||||||
|
|
||||||
val optGreater2 = atomic { refGreater2.get }
|
val optGreater2 = atomic { refGreater2.get }
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
package se.scalablesolutions.akka.security
|
package se.scalablesolutions.akka.security
|
||||||
|
|
||||||
import se.scalablesolutions.akka.actor.{Scheduler, Actor, ActorRegistry}
|
import se.scalablesolutions.akka.actor.{Scheduler, Actor, ActorID, ActorRegistry}
|
||||||
import se.scalablesolutions.akka.util.Logging
|
import se.scalablesolutions.akka.util.Logging
|
||||||
import se.scalablesolutions.akka.config.Config
|
import se.scalablesolutions.akka.config.Config
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ case class SpnegoCredentials(token: Array[Byte]) extends Credentials
|
||||||
* Jersey Filter for invocation intercept and authorization/authentication
|
* Jersey Filter for invocation intercept and authorization/authentication
|
||||||
*/
|
*/
|
||||||
class AkkaSecurityFilterFactory extends ResourceFilterFactory with Logging {
|
class AkkaSecurityFilterFactory extends ResourceFilterFactory with Logging {
|
||||||
class Filter(actor: Actor, rolesAllowed: Option[List[String]])
|
class Filter(actor: ActorID, rolesAllowed: Option[List[String]])
|
||||||
extends ResourceFilter with ContainerRequestFilter with Logging {
|
extends ResourceFilter with ContainerRequestFilter with Logging {
|
||||||
|
|
||||||
override def getRequestFilter: ContainerRequestFilter = this
|
override def getRequestFilter: ContainerRequestFilter = this
|
||||||
|
|
@ -111,7 +111,7 @@ class AkkaSecurityFilterFactory extends ResourceFilterFactory with Logging {
|
||||||
* Currently we always take the first, since there usually should be at most one authentication actor, but a round-robin
|
* Currently we always take the first, since there usually should be at most one authentication actor, but a round-robin
|
||||||
* strategy could be implemented in the future
|
* strategy could be implemented in the future
|
||||||
*/
|
*/
|
||||||
def authenticator: Actor = ActorRegistry.actorsFor(authenticatorFQN).head
|
def authenticator: ActorID = ActorRegistry.actorsFor(authenticatorFQN).head
|
||||||
|
|
||||||
def mkFilter(roles: Option[List[String]]): java.util.List[ResourceFilter] =
|
def mkFilter(roles: Option[List[String]]): java.util.List[ResourceFilter] =
|
||||||
java.util.Collections.singletonList(new Filter(authenticator, roles))
|
java.util.Collections.singletonList(new Filter(authenticator, roles))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue