diff --git a/.gitignore b/.gitignore
index 55bcf5ee42..91a3be7969 100755
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ project/boot/*
lib_managed
etags
TAGS
+akka.tmproj
reports
dist
build
@@ -32,9 +33,11 @@ tm.out
*.iws
*.ipr
*.iml
+run-codefellow
.project
.settings
.classpath
.idea
.scala_dependencies
-multiverse.log
\ No newline at end of file
+multiverse.log
+.eprj
\ No newline at end of file
diff --git a/akka-active-object-test/pom.xml b/akka-active-object-test/pom.xml
index dffacd8db0..e498c34d32 100644
--- a/akka-active-object-test/pom.xml
+++ b/akka-active-object-test/pom.xml
@@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
- Akka Active Object Tests in Java
+ Akka TypedActor Tests in Javaakka-active-object-testse.scalablesolutions.akka0.9
diff --git a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/AllTest.java b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/AllTest.java
index 465c9da182..77739f6ff1 100644
--- a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/AllTest.java
+++ b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/AllTest.java
@@ -10,7 +10,7 @@ public class AllTest extends TestCase {
suite.addTestSuite(InMemoryStateTest.class);
suite.addTestSuite(InMemNestedStateTest.class);
suite.addTestSuite(RemoteInMemoryStateTest.class);
- suite.addTestSuite(ActiveObjectGuiceConfiguratorTest.class);
+ suite.addTestSuite(TypedActorGuiceConfiguratorTest.class);
return suite;
}
diff --git a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemNestedStateTest.java b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemNestedStateTest.java
index 746df950bf..db9d4d4146 100644
--- a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemNestedStateTest.java
+++ b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemNestedStateTest.java
@@ -6,7 +6,7 @@ package se.scalablesolutions.akka.api;
import se.scalablesolutions.akka.config.*;
import se.scalablesolutions.akka.config.Config;
-import se.scalablesolutions.akka.config.ActiveObjectConfigurator;
+import se.scalablesolutions.akka.config.TypedActorConfigurator;
import static se.scalablesolutions.akka.config.JavaConfig.*;
import se.scalablesolutions.akka.actor.*;
import junit.framework.TestCase;
@@ -14,7 +14,7 @@ import junit.framework.TestCase;
public class InMemNestedStateTest extends TestCase {
static String messageLog = "";
- final private ActiveObjectConfigurator conf = new ActiveObjectConfigurator();
+ final private TypedActorConfigurator conf = new TypedActorConfigurator();
public InMemNestedStateTest() {
conf.configure(
diff --git a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemoryStateTest.java b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemoryStateTest.java
index 3708d58acc..6562d0d611 100644
--- a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemoryStateTest.java
+++ b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/InMemoryStateTest.java
@@ -8,7 +8,7 @@ import junit.framework.TestCase;
import se.scalablesolutions.akka.config.Config;
import se.scalablesolutions.akka.config.*;
-import se.scalablesolutions.akka.config.ActiveObjectConfigurator;
+import se.scalablesolutions.akka.config.TypedActorConfigurator;
import static se.scalablesolutions.akka.config.JavaConfig.*;
@@ -17,7 +17,7 @@ import se.scalablesolutions.akka.actor.*;
public class InMemoryStateTest extends TestCase {
static String messageLog = "";
- final private ActiveObjectConfigurator conf = new ActiveObjectConfigurator();
+ final private TypedActorConfigurator conf = new TypedActorConfigurator();
public InMemoryStateTest() {
Config.config();
diff --git a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/MiscActiveObjectTest.java b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/MiscActiveObjectTest.java
index e61b8ac07d..aaa97d3587 100644
--- a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/MiscActiveObjectTest.java
+++ b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/MiscActiveObjectTest.java
@@ -1,7 +1,7 @@
package se.scalablesolutions.akka.api;
-import static se.scalablesolutions.akka.actor.ActiveObject.link;
-import static se.scalablesolutions.akka.actor.ActiveObject.newInstance;
+import static se.scalablesolutions.akka.actor.TypedActor.link;
+import static se.scalablesolutions.akka.actor.TypedActor.newInstance;
import org.junit.Assert;
import org.junit.Test;
@@ -15,7 +15,7 @@ import junit.framework.TestCase;
* @author johanrask
*
*/
-public class MiscActiveObjectTest extends TestCase {
+public class MiscTypedActorTest extends TestCase {
/**
diff --git a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/RemoteInMemoryStateTest.java b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/RemoteInMemoryStateTest.java
index d4b4fd7687..3ae8b647ab 100644
--- a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/RemoteInMemoryStateTest.java
+++ b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/RemoteInMemoryStateTest.java
@@ -5,8 +5,8 @@
package se.scalablesolutions.akka.api;
import se.scalablesolutions.akka.config.Config;
-import se.scalablesolutions.akka.actor.ActiveObject;
-import se.scalablesolutions.akka.config.ActiveObjectConfigurator;
+import se.scalablesolutions.akka.actor.TypedActor;
+import se.scalablesolutions.akka.config.TypedActorConfigurator;
import se.scalablesolutions.akka.remote.RemoteNode;
import junit.framework.TestCase;
@@ -23,14 +23,14 @@ public class RemoteInMemoryStateTest extends TestCase {
try { Thread.currentThread().sleep(1000); } catch (Exception e) {}
Config.config();
}
- final ActiveObjectConfigurator conf = new ActiveObjectConfigurator();
+ final TypedActorConfigurator conf = new TypedActorConfigurator();
protected void tearDown() {
conf.stop();
}
public void testMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
- InMemStateful stateful = ActiveObject.newRemoteInstance(InMemStateful.class, 1000, "localhost", 9999);
+ InMemStateful stateful = TypedActor.newRemoteInstance(InMemStateful.class, 1000, "localhost", 9999);
stateful.init();
stateful.setMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init"); // set init state
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactionrequired
@@ -38,10 +38,10 @@ public class RemoteInMemoryStateTest extends TestCase {
}
public void testMapShouldRollbackStateForStatefulServerInCaseOfFailure() {
- InMemStateful stateful = ActiveObject.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
+ InMemStateful stateful = TypedActor.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
stateful.init();
stateful.setMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init"); // set init state
- InMemFailer failer = ActiveObject.newRemoteInstance(InMemFailer.class, 1000, "localhost", 9999); //conf.getInstance(InMemFailer.class);
+ InMemFailer failer = TypedActor.newRemoteInstance(InMemFailer.class, 1000, "localhost", 9999); //conf.getInstance(InMemFailer.class);
try {
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactionrequired method
fail("should have thrown an exception");
@@ -51,7 +51,7 @@ public class RemoteInMemoryStateTest extends TestCase {
}
public void testVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
- InMemStateful stateful = ActiveObject.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
+ InMemStateful stateful = TypedActor.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
stateful.init();
stateful.setVectorState("init"); // set init state
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactionrequired
@@ -59,10 +59,10 @@ public class RemoteInMemoryStateTest extends TestCase {
}
public void testVectorShouldRollbackStateForStatefulServerInCaseOfFailure() {
- InMemStateful stateful = ActiveObject.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
+ InMemStateful stateful = TypedActor.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
stateful.init();
stateful.setVectorState("init"); // set init state
- InMemFailer failer = ActiveObject.newRemoteInstance(InMemFailer.class, 10000, "localhost", 9999); //conf.getInstance(InMemFailer.class);
+ InMemFailer failer = TypedActor.newRemoteInstance(InMemFailer.class, 10000, "localhost", 9999); //conf.getInstance(InMemFailer.class);
try {
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactionrequired method
fail("should have thrown an exception");
@@ -72,7 +72,7 @@ public class RemoteInMemoryStateTest extends TestCase {
}
public void testRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
- InMemStateful stateful = ActiveObject.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
+ InMemStateful stateful = TypedActor.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
stateful.init();
stateful.setRefState("init"); // set init state
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactionrequired
@@ -80,10 +80,10 @@ public class RemoteInMemoryStateTest extends TestCase {
}
public void testRefShouldRollbackStateForStatefulServerInCaseOfFailure() {
- InMemStateful stateful = ActiveObject.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
+ InMemStateful stateful = TypedActor.newRemoteInstance(InMemStateful.class, 10000, "localhost", 9999);
stateful.init();
stateful.setRefState("init"); // set init state
- InMemFailer failer = ActiveObject.newRemoteInstance(InMemFailer.class, 10000, "localhost", 9999); //conf.getInstance(InMemFailer.class);
+ InMemFailer failer = TypedActor.newRemoteInstance(InMemFailer.class, 10000, "localhost", 9999); //conf.getInstance(InMemFailer.class);
try {
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactionrequired method
fail("should have thrown an exception");
diff --git a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/ActiveObjectGuiceConfiguratorTest.java b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/TypedActorGuiceConfiguratorTest.java
similarity index 87%
rename from akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/ActiveObjectGuiceConfiguratorTest.java
rename to akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/TypedActorGuiceConfiguratorTest.java
index 69f74ec537..e604b4da69 100644
--- a/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/ActiveObjectGuiceConfiguratorTest.java
+++ b/akka-active-object-test/src/test/java/se/scalablesolutions/akka/api/TypedActorGuiceConfiguratorTest.java
@@ -10,14 +10,14 @@ import com.google.inject.Scopes;
import junit.framework.TestCase;
import se.scalablesolutions.akka.config.Config;
-import se.scalablesolutions.akka.config.ActiveObjectConfigurator;
+import se.scalablesolutions.akka.config.TypedActorConfigurator;
import static se.scalablesolutions.akka.config.JavaConfig.*;
import se.scalablesolutions.akka.dispatch.*;
-public class ActiveObjectGuiceConfiguratorTest extends TestCase {
+public class TypedActorGuiceConfiguratorTest extends TestCase {
static String messageLog = "";
- final private ActiveObjectConfigurator conf = new ActiveObjectConfigurator();
+ final private TypedActorConfigurator conf = new TypedActorConfigurator();
protected void setUp() {
Config.config();
@@ -46,7 +46,7 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
}
- public void testGuiceActiveObjectInjection() {
+ public void testGuiceTypedActorInjection() {
messageLog = "";
Foo foo = conf.getInstance(Foo.class);
Bar bar = conf.getInstance(Bar.class);
@@ -69,7 +69,7 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
}
}
- public void testActiveObjectInvocation() throws InterruptedException {
+ public void testTypedActorInvocation() throws InterruptedException {
messageLog = "";
Foo foo = conf.getInstance(Foo.class);
messageLog += foo.foo("foo ");
@@ -79,7 +79,7 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
assertEquals("foo return_foo before_bar ", messageLog);
}
- public void testActiveObjectInvocationsInvocation() throws InterruptedException {
+ public void testTypedActorInvocationsInvocation() throws InterruptedException {
messageLog = "";
Foo foo = conf.getInstance(Foo.class);
Bar bar = conf.getInstance(Bar.class);
diff --git a/akka-amqp/src/main/scala/AMQP.scala b/akka-amqp/src/main/scala/AMQP.scala
index 8605401dbd..0bfbd93063 100644
--- a/akka-amqp/src/main/scala/AMQP.scala
+++ b/akka-amqp/src/main/scala/AMQP.scala
@@ -136,8 +136,8 @@ object AMQP {
def toBinary(t: T): Array[Byte]
}
-
+
case class RpcClientSerializer[O,I](toBinary: ToBinary[O], fromBinary: FromBinary[I])
-
+
case class RpcServerSerializer[I,O](fromBinary: FromBinary[I], toBinary: ToBinary[O])
}
diff --git a/akka-amqp/src/main/scala/ConsumerActor.scala b/akka-amqp/src/main/scala/ConsumerActor.scala
index 26d1ac00db..d394e9d997 100644
--- a/akka-amqp/src/main/scala/ConsumerActor.scala
+++ b/akka-amqp/src/main/scala/ConsumerActor.scala
@@ -14,7 +14,7 @@ import java.lang.Throwable
private[amqp] class ConsumerActor(consumerParameters: ConsumerParameters)
extends FaultTolerantChannelActor(consumerParameters.exchangeParameters, consumerParameters.channelParameters) {
-
+
import consumerParameters._
import exchangeParameters._
diff --git a/akka-amqp/src/main/scala/FaultTolerantChannelActor.scala b/akka-amqp/src/main/scala/FaultTolerantChannelActor.scala
index 40bcd5de57..5ecae4c6d3 100644
--- a/akka-amqp/src/main/scala/FaultTolerantChannelActor.scala
+++ b/akka-amqp/src/main/scala/FaultTolerantChannelActor.scala
@@ -14,7 +14,7 @@ import se.scalablesolutions.akka.amqp.AMQP.{ExchangeParameters, ChannelParameter
abstract private[amqp] class FaultTolerantChannelActor(
exchangeParameters: ExchangeParameters, channelParameters: Option[ChannelParameters]) extends Actor {
-
+
import exchangeParameters._
protected[amqp] var channel: Option[Channel] = None
@@ -104,4 +104,4 @@ abstract private[amqp] class FaultTolerantChannelActor(
}
override def shutdown = closeChannel
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/main/scala/ProducerActor.scala b/akka-amqp/src/main/scala/ProducerActor.scala
index db290a5ac1..48a6be0a94 100644
--- a/akka-amqp/src/main/scala/ProducerActor.scala
+++ b/akka-amqp/src/main/scala/ProducerActor.scala
@@ -9,7 +9,7 @@ import se.scalablesolutions.akka.amqp.AMQP.ProducerParameters
private[amqp] class ProducerActor(producerParameters: ProducerParameters)
extends FaultTolerantChannelActor(producerParameters.exchangeParameters, producerParameters.channelParameters) {
-
+
import producerParameters._
import exchangeParameters._
diff --git a/akka-amqp/src/main/scala/RpcClientActor.scala b/akka-amqp/src/main/scala/RpcClientActor.scala
index f8c376be7e..2935982a67 100644
--- a/akka-amqp/src/main/scala/RpcClientActor.scala
+++ b/akka-amqp/src/main/scala/RpcClientActor.scala
@@ -4,6 +4,9 @@
package se.scalablesolutions.akka.amqp
+import se.scalablesolutions.akka.serialization.Serializer
+import se.scalablesolutions.akka.amqp.AMQP.{ChannelParameters, ExchangeParameters}
+
import com.rabbitmq.client.{Channel, RpcClient}
import se.scalablesolutions.akka.amqp.AMQP.{RpcClientSerializer, ChannelParameters, ExchangeParameters}
@@ -20,7 +23,6 @@ class RpcClientActor[I,O](exchangeParameters: ExchangeParameters,
def specificMessageHandler = {
case payload: I => {
-
rpcClient match {
case Some(client) =>
val response: Array[Byte] = client.primitiveCall(serializer.toBinary.toBinary(payload))
@@ -30,18 +32,12 @@ class RpcClientActor[I,O](exchangeParameters: ExchangeParameters,
}
}
- protected def setupChannel(ch: Channel) = {
- rpcClient = Some(new RpcClient(ch, exchangeName, routingKey))
- }
+ protected def setupChannel(ch: Channel) = rpcClient = Some(new RpcClient(ch, exchangeName, routingKey))
override def preRestart(reason: Throwable) = {
rpcClient = None
super.preRestart(reason)
}
-
- override def toString(): String =
- "AMQP.RpcClient[exchange=" +exchangeName +
- ", routingKey=" + routingKey+ "]"
-
-}
\ No newline at end of file
+ override def toString = "AMQP.RpcClient[exchange=" +exchangeName + ", routingKey=" + routingKey+ "]"
+}
diff --git a/akka-amqp/src/main/scala/RpcServerActor.scala b/akka-amqp/src/main/scala/RpcServerActor.scala
index 897c041c69..c64ef9058e 100644
--- a/akka-amqp/src/main/scala/RpcServerActor.scala
+++ b/akka-amqp/src/main/scala/RpcServerActor.scala
@@ -31,4 +31,4 @@ class RpcServerActor[I,O](producer: ActorRef, serializer: RpcServerSerializer[I,
override def toString(): String =
"AMQP.RpcServer[]"
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPConnectionRecoveryTest.scala b/akka-amqp/src/test/scala/AMQPConnectionRecoveryTest.scala
index 3bc2cb20dd..c1af35546a 100644
--- a/akka-amqp/src/test/scala/AMQPConnectionRecoveryTest.scala
+++ b/akka-amqp/src/test/scala/AMQPConnectionRecoveryTest.scala
@@ -56,4 +56,4 @@ class AMQPConnectionRecoveryTest extends JUnitSuite with MustMatchers with Loggi
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPConsumerChannelRecoveryTest.scala b/akka-amqp/src/test/scala/AMQPConsumerChannelRecoveryTest.scala
index 0f6fadfcc4..a0b44f4739 100644
--- a/akka-amqp/src/test/scala/AMQPConsumerChannelRecoveryTest.scala
+++ b/akka-amqp/src/test/scala/AMQPConsumerChannelRecoveryTest.scala
@@ -67,4 +67,4 @@ class AMQPConsumerChannelRecoveryTest extends JUnitSuite with MustMatchers with
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPConsumerConnectionRecoveryTest.scala b/akka-amqp/src/test/scala/AMQPConsumerConnectionRecoveryTest.scala
index 9dccd43be8..bf4885fea5 100644
--- a/akka-amqp/src/test/scala/AMQPConsumerConnectionRecoveryTest.scala
+++ b/akka-amqp/src/test/scala/AMQPConsumerConnectionRecoveryTest.scala
@@ -86,4 +86,4 @@ class AMQPConsumerConnectionRecoveryTest extends JUnitSuite with MustMatchers wi
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPConsumerManualAcknowledgeTest.scala b/akka-amqp/src/test/scala/AMQPConsumerManualAcknowledgeTest.scala
index d48f38afc5..2dc4ee939b 100644
--- a/akka-amqp/src/test/scala/AMQPConsumerManualAcknowledgeTest.scala
+++ b/akka-amqp/src/test/scala/AMQPConsumerManualAcknowledgeTest.scala
@@ -64,4 +64,4 @@ class AMQPConsumerManualAcknowledgeTest extends JUnitSuite with MustMatchers wit
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPConsumerMessageTest.scala b/akka-amqp/src/test/scala/AMQPConsumerMessageTest.scala
index af94b0a515..5d34f867d6 100644
--- a/akka-amqp/src/test/scala/AMQPConsumerMessageTest.scala
+++ b/akka-amqp/src/test/scala/AMQPConsumerMessageTest.scala
@@ -38,7 +38,7 @@ class AMQPConsumerMessageTest extends JUnitSuite with MustMatchers with Logging
val producer = AMQP.newProducer(connection,
ProducerParameters(exchangeParameters, channelParameters = Some(channelParameters)))
-
+
countDown.await(2, TimeUnit.SECONDS) must be (true)
producer ! Message("some_payload".getBytes, "non.interesting.routing.key")
payloadLatch.tryAwait(2, TimeUnit.SECONDS) must be (true)
@@ -53,4 +53,4 @@ class AMQPConsumerMessageTest extends JUnitSuite with MustMatchers with Logging
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPProducerChannelRecoveryTest.scala b/akka-amqp/src/test/scala/AMQPProducerChannelRecoveryTest.scala
index 095a21fc86..26b2d78393 100644
--- a/akka-amqp/src/test/scala/AMQPProducerChannelRecoveryTest.scala
+++ b/akka-amqp/src/test/scala/AMQPProducerChannelRecoveryTest.scala
@@ -60,4 +60,4 @@ class AMQPProducerChannelRecoveryTest extends JUnitSuite with MustMatchers with
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPProducerConnectionRecoveryTest.scala b/akka-amqp/src/test/scala/AMQPProducerConnectionRecoveryTest.scala
index 71bc08bdaa..fe8259b208 100644
--- a/akka-amqp/src/test/scala/AMQPProducerConnectionRecoveryTest.scala
+++ b/akka-amqp/src/test/scala/AMQPProducerConnectionRecoveryTest.scala
@@ -59,4 +59,4 @@ class AMQPProducerConnectionRecoveryTest extends JUnitSuite with MustMatchers wi
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPProducerMessageTest.scala b/akka-amqp/src/test/scala/AMQPProducerMessageTest.scala
index ab9bb00e7c..5b19df351f 100644
--- a/akka-amqp/src/test/scala/AMQPProducerMessageTest.scala
+++ b/akka-amqp/src/test/scala/AMQPProducerMessageTest.scala
@@ -21,7 +21,7 @@ class AMQPProducerMessageTest extends JUnitSuite with MustMatchers with Logging
@Test
def producerMessage = if (AMQPTest.enabled) {
-
+
val connection: ActorRef = AMQP.newConnection()
try {
val returnLatch = new StandardLatch
@@ -48,4 +48,4 @@ class AMQPProducerMessageTest extends JUnitSuite with MustMatchers with Logging
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPRpcClientServerTest.scala b/akka-amqp/src/test/scala/AMQPRpcClientServerTest.scala
index 7dbfb4becd..dcaec4cd06 100644
--- a/akka-amqp/src/test/scala/AMQPRpcClientServerTest.scala
+++ b/akka-amqp/src/test/scala/AMQPRpcClientServerTest.scala
@@ -68,4 +68,4 @@ class AMQPRpcClientServerTest extends JUnitSuite with MustMatchers with Logging
// this dummy test makes sure that the whole test class doesn't fail because of missing tests
assert(true)
}
-}
\ No newline at end of file
+}
diff --git a/akka-amqp/src/test/scala/AMQPTest.scala b/akka-amqp/src/test/scala/AMQPTest.scala
index e50ab673f6..5ff9157bc5 100644
--- a/akka-amqp/src/test/scala/AMQPTest.scala
+++ b/akka-amqp/src/test/scala/AMQPTest.scala
@@ -6,4 +6,4 @@ package se.scalablesolutions.akka.amqp.test
object AMQPTest {
def enabled = false
-}
\ No newline at end of file
+}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/consume.java b/akka-camel/src/main/java/se/scalablesolutions/akka/annotation/consume.java
similarity index 89%
rename from akka-core/src/main/java/se/scalablesolutions/akka/annotation/consume.java
rename to akka-camel/src/main/java/se/scalablesolutions/akka/annotation/consume.java
index 1a8e5c8db6..34d42debab 100644
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/consume.java
+++ b/akka-camel/src/main/java/se/scalablesolutions/akka/annotation/consume.java
@@ -10,7 +10,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD})
+@Target({ElementType.METHOD})
public @interface consume {
public abstract String value();
diff --git a/akka-camel/src/main/resources/META-INF/services/org/apache/camel/component/active-object b/akka-camel/src/main/resources/META-INF/services/org/apache/camel/component/active-object
deleted file mode 100644
index 5dd88a0671..0000000000
--- a/akka-camel/src/main/resources/META-INF/services/org/apache/camel/component/active-object
+++ /dev/null
@@ -1 +0,0 @@
-class=se.scalablesolutions.akka.camel.component.ActiveObjectComponent
\ No newline at end of file
diff --git a/akka-camel/src/main/resources/META-INF/services/org/apache/camel/component/typed-actor b/akka-camel/src/main/resources/META-INF/services/org/apache/camel/component/typed-actor
new file mode 100644
index 0000000000..e004d887b3
--- /dev/null
+++ b/akka-camel/src/main/resources/META-INF/services/org/apache/camel/component/typed-actor
@@ -0,0 +1 @@
+class=se.scalablesolutions.akka.camel.component.TypedActorComponent
\ No newline at end of file
diff --git a/akka-camel/src/main/scala/CamelContextLifecycle.scala b/akka-camel/src/main/scala/CamelContextLifecycle.scala
index 640ba14e36..05c18396b8 100644
--- a/akka-camel/src/main/scala/CamelContextLifecycle.scala
+++ b/akka-camel/src/main/scala/CamelContextLifecycle.scala
@@ -9,7 +9,7 @@ import java.util.Map
import org.apache.camel.{ProducerTemplate, CamelContext}
import org.apache.camel.impl.DefaultCamelContext
-import se.scalablesolutions.akka.camel.component.ActiveObjectComponent
+import se.scalablesolutions.akka.camel.component.TypedActorComponent
import se.scalablesolutions.akka.util.Logging
/**
@@ -29,15 +29,15 @@ trait CamelContextLifecycle extends Logging {
private var _started = false
/**
- * Camel component for accessing active objects.
+ * Camel component for accessing typed actors.
*/
- private[camel] var activeObjectComponent: ActiveObjectComponent = _
+ private[camel] var typedActorComponent: TypedActorComponent = _
/**
- * Registry in which active objects are TEMPORARILY registered during
- * creation of Camel routes to active objects.
+ * Registry in which typed actors are TEMPORARILY registered during
+ * creation of Camel routes to typed actors.
*/
- private[camel] var activeObjectRegistry: Map[String, AnyRef] = _
+ private[camel] var typedActorRegistry: Map[String, AnyRef] = _
/**
* Returns the managed CamelContext.
@@ -93,15 +93,15 @@ trait CamelContextLifecycle extends Logging {
* CamelContext stream-caching is enabled. If applications want to disable stream-
* caching they can do so after this method returned and prior to calling start.
* This method also registers a new
- * {@link se.scalablesolutions.akka.camel.component.ActiveObjectComponent} at
- * context under a name defined by ActiveObjectComponent.InternalSchema.
+ * {@link se.scalablesolutions.akka.camel.component.TypedActorComponent} at
+ * context under a name defined by TypedActorComponent.InternalSchema.
*/
def init(context: CamelContext) {
- this.activeObjectComponent = new ActiveObjectComponent
- this.activeObjectRegistry = activeObjectComponent.activeObjectRegistry
+ this.typedActorComponent = new TypedActorComponent
+ this.typedActorRegistry = typedActorComponent.typedActorRegistry
this.context = context
this.context.setStreamCaching(true)
- this.context.addComponent(ActiveObjectComponent.InternalSchema, activeObjectComponent)
+ this.context.addComponent(TypedActorComponent.InternalSchema, typedActorComponent)
this.template = context.createProducerTemplate
_initialized = true
log.info("Camel context initialized")
diff --git a/akka-camel/src/main/scala/CamelService.scala b/akka-camel/src/main/scala/CamelService.scala
index 65a6a44fe5..163daecf0d 100644
--- a/akka-camel/src/main/scala/CamelService.scala
+++ b/akka-camel/src/main/scala/CamelService.scala
@@ -1,15 +1,18 @@
/**
* Copyright (C) 2009-2010 Scalable Solutions AB
*/
-
package se.scalablesolutions.akka.camel
+import java.util.concurrent.CountDownLatch
+
+import org.apache.camel.CamelContext
+
import se.scalablesolutions.akka.actor.Actor._
import se.scalablesolutions.akka.actor.{AspectInitRegistry, ActorRegistry}
import se.scalablesolutions.akka.util.{Bootable, Logging}
/**
- * Used by applications (and the Kernel) to publish consumer actors and active objects via
+ * Used by applications (and the Kernel) to publish consumer actors and typed actors via
* Camel endpoints and to manage the life cycle of a a global CamelContext which can be
* accessed via se.scalablesolutions.akka.camel.CamelContextManager.context.
*
@@ -32,8 +35,8 @@ trait CamelService extends Bootable with Logging {
* Starts the CamelService. Any started actor that is a consumer actor will be (asynchronously)
* published as Camel endpoint. Consumer actors that are started after this method returned will
* be published as well. Actor publishing is done asynchronously. A started (loaded) CamelService
- * also publishes @consume annotated methods of active objects that have been created
- * with ActiveObject.newInstance(..) (and ActiveObject.newInstance(..)
+ * also publishes @consume annotated methods of typed actors that have been created
+ * with TypedActor.newInstance(..) (and TypedActor.newInstance(..)
* on a remote node).
*/
abstract override def onLoad = {
@@ -43,7 +46,7 @@ trait CamelService extends Bootable with Logging {
if (!initialized) init
if (!started) start
- // start actor that exposes consumer actors and active objects via Camel endpoints
+ // start actor that exposes consumer actors and typed actors via Camel endpoints
consumerPublisher.start
// init publishRequestor so that buffered and future events are delivered to consumerPublisher
@@ -77,27 +80,53 @@ trait CamelService extends Bootable with Logging {
* @see onUnload
*/
def unload = onUnload
+
+ /**
+ * Sets an expectation of the number of upcoming endpoint activations and returns
+ * a {@link CountDownLatch} that can be used to wait for the activations to occur.
+ * Endpoint activations that occurred in the past are not considered.
+ */
+ def expectEndpointActivationCount(count: Int): CountDownLatch =
+ (consumerPublisher !! SetExpectedRegistrationCount(count)).as[CountDownLatch].get
+
+ /**
+ * Sets an expectation of the number of upcoming endpoint de-activations and returns
+ * a {@link CountDownLatch} that can be used to wait for the de-activations to occur.
+ * Endpoint de-activations that occurred in the past are not considered.
+ */
+ def expectEndpointDeactivationCount(count: Int): CountDownLatch =
+ (consumerPublisher !! SetExpectedUnregistrationCount(count)).as[CountDownLatch].get
}
/**
- * CamelService companion object used by standalone applications to create their own
- * CamelService instance.
+ * Single CamelService instance.
*
* @author Martin Krasser
*/
-object CamelService {
+object CamelService extends CamelService {
/**
- * Creates a new CamelService instance.
+ * Starts the CamelService singleton.
*/
- def newInstance: CamelService = new DefaultCamelService
+ def start = load
+
+ /**
+ * Stops the CamelService singleton.
+ */
+ def stop = unload
}
-/**
- * Default CamelService implementation to be created in Java applications with
- *
- * CamelService service = new DefaultCamelService()
- *
- */
-class DefaultCamelService extends CamelService {
+object CamelServiceFactory {
+ /**
+ * Creates a new CamelService instance
+ */
+ def createCamelService: CamelService = new CamelService { }
+
+ /**
+ * Creates a new CamelService instance
+ */
+ def createCamelService(camelContext: CamelContext): CamelService = {
+ CamelContextManager.init(camelContext)
+ createCamelService
+ }
}
diff --git a/akka-camel/src/main/scala/Consumer.scala b/akka-camel/src/main/scala/Consumer.scala
index caafca4628..1f7dffc91b 100644
--- a/akka-camel/src/main/scala/Consumer.scala
+++ b/akka-camel/src/main/scala/Consumer.scala
@@ -4,7 +4,7 @@
package se.scalablesolutions.akka.camel
-import se.scalablesolutions.akka.actor.Actor
+import se.scalablesolutions.akka.actor.{ActorRef, Actor}
/**
* Mixed in by Actor implementations that consume message from Camel endpoints.
@@ -12,9 +12,34 @@ import se.scalablesolutions.akka.actor.Actor
* @author Martin Krasser
*/
trait Consumer { self: Actor =>
-
/**
* Returns the Camel endpoint URI to consume messages from.
*/
def endpointUri: String
+
+ /**
+ * Determines whether two-way communications with this consumer actor should
+ * be done in blocking or non-blocking mode (default is non-blocking). One-way
+ * communications never block.
+ */
+ def blocking = false
+}
+
+/**
+ * @author Martin Krasser
+ */
+private[camel] object Consumer {
+ /**
+ * Applies a function f to actorRef if actorRef
+ * references a consumer actor. A valid reference to a consumer actor is a local actor
+ * reference with a target actor that implements the Consumer trait. The
+ * target Consumer object is passed as argument to f. This
+ * method returns None if actorRef is not a valid reference
+ * to a consumer actor, Some result otherwise.
+ */
+ def forConsumer[T](actorRef: ActorRef)(f: Consumer => T): Option[T] = {
+ if (!actorRef.actor.isInstanceOf[Consumer]) None
+ else if (actorRef.remoteAddress.isDefined) None
+ else Some(f(actorRef.actor.asInstanceOf[Consumer]))
+ }
}
diff --git a/akka-camel/src/main/scala/ConsumerPublisher.scala b/akka-camel/src/main/scala/ConsumerPublisher.scala
index 8d29739f02..8c01b2079d 100644
--- a/akka-camel/src/main/scala/ConsumerPublisher.scala
+++ b/akka-camel/src/main/scala/ConsumerPublisher.scala
@@ -13,7 +13,7 @@ import org.apache.camel.builder.RouteBuilder
import se.scalablesolutions.akka.actor._
import se.scalablesolutions.akka.actor.annotation.consume
-import se.scalablesolutions.akka.camel.component.ActiveObjectComponent
+import se.scalablesolutions.akka.camel.component.TypedActorComponent
import se.scalablesolutions.akka.util.Logging
/**
@@ -24,7 +24,7 @@ private[camel] object ConsumerPublisher extends Logging {
* Creates a route to the registered consumer actor.
*/
def handleConsumerRegistered(event: ConsumerRegistered) {
- CamelContextManager.context.addRoutes(new ConsumerActorRoute(event.uri, event.id, event.uuid))
+ CamelContextManager.context.addRoutes(new ConsumerActorRoute(event.uri, event.uuid, event.blocking))
log.info("published actor %s at endpoint %s" format (event.actorRef, event.uri))
}
@@ -32,20 +32,20 @@ private[camel] object ConsumerPublisher extends Logging {
* Stops route to the already un-registered consumer actor.
*/
def handleConsumerUnregistered(event: ConsumerUnregistered) {
- CamelContextManager.context.stopRoute(event.id)
+ CamelContextManager.context.stopRoute(event.uuid)
log.info("unpublished actor %s from endpoint %s" format (event.actorRef, event.uri))
}
/**
- * Creates a route to an active object method.
+ * Creates a route to an typed actor method.
*/
def handleConsumerMethodRegistered(event: ConsumerMethodRegistered) {
val targetMethod = event.method.getName
val objectId = "%s_%s" format (event.init.actorRef.uuid, targetMethod)
- CamelContextManager.activeObjectRegistry.put(objectId, event.activeObject)
+ CamelContextManager.typedActorRegistry.put(objectId, event.typedActor)
CamelContextManager.context.addRoutes(new ConsumerMethodRoute(event.uri, objectId, targetMethod))
- log.info("published method %s of %s at endpoint %s" format (targetMethod, event.activeObject, event.uri))
+ log.info("published method %s of %s at endpoint %s" format (targetMethod, event.typedActor, event.uri))
}
/**
@@ -55,66 +55,66 @@ private[camel] object ConsumerPublisher extends Logging {
val targetMethod = event.method.getName
val objectId = "%s_%s" format (event.init.actorRef.uuid, targetMethod)
- CamelContextManager.activeObjectRegistry.remove(objectId)
+ CamelContextManager.typedActorRegistry.remove(objectId)
CamelContextManager.context.stopRoute(objectId)
- log.info("unpublished method %s of %s from endpoint %s" format (targetMethod, event.activeObject, event.uri))
+ log.info("unpublished method %s of %s from endpoint %s" format (targetMethod, event.typedActor, event.uri))
}
}
/**
- * Actor that publishes consumer actors and active object methods at Camel endpoints.
+ * Actor that publishes consumer actors and typed actor methods at Camel endpoints.
* The Camel context used for publishing is CamelContextManager.context. This actor
* accepts messages of type
- * se.scalablesolutions.akka.camel.service.ConsumerRegistered,
- * se.scalablesolutions.akka.camel.service.ConsumerMethodRegistered and
- * se.scalablesolutions.akka.camel.service.ConsumerUnregistered.
+ * se.scalablesolutions.akka.camel.ConsumerRegistered,
+ * se.scalablesolutions.akka.camel.ConsumerUnregistered.
+ * se.scalablesolutions.akka.camel.ConsumerMethodRegistered and
+ * se.scalablesolutions.akka.camel.ConsumerMethodUnregistered.
*
* @author Martin Krasser
*/
private[camel] class ConsumerPublisher extends Actor {
import ConsumerPublisher._
- @volatile private var latch = new CountDownLatch(0)
+ @volatile private var registrationLatch = new CountDownLatch(0)
+ @volatile private var unregistrationLatch = new CountDownLatch(0)
- /**
- * Adds a route to the actor identified by a Publish message to the global CamelContext.
- */
protected def receive = {
case r: ConsumerRegistered => {
handleConsumerRegistered(r)
- latch.countDown // needed for testing only.
+ registrationLatch.countDown
}
case u: ConsumerUnregistered => {
handleConsumerUnregistered(u)
- latch.countDown // needed for testing only.
+ unregistrationLatch.countDown
}
case mr: ConsumerMethodRegistered => {
handleConsumerMethodRegistered(mr)
- latch.countDown // needed for testing only.
+ registrationLatch.countDown
}
case mu: ConsumerMethodUnregistered => {
handleConsumerMethodUnregistered(mu)
- latch.countDown // needed for testing only.
+ unregistrationLatch.countDown
}
- case SetExpectedMessageCount(num) => {
- // needed for testing only.
- latch = new CountDownLatch(num)
- self.reply(latch)
+ case SetExpectedRegistrationCount(num) => {
+ registrationLatch = new CountDownLatch(num)
+ self.reply(registrationLatch)
+ }
+ case SetExpectedUnregistrationCount(num) => {
+ unregistrationLatch = new CountDownLatch(num)
+ self.reply(unregistrationLatch)
}
case _ => { /* ignore */}
}
}
-/**
- * Command message used For testing-purposes only.
- */
-private[camel] case class SetExpectedMessageCount(num: Int)
+private[camel] case class SetExpectedRegistrationCount(num: Int)
+private[camel] case class SetExpectedUnregistrationCount(num: Int)
/**
- * Defines an abstract route to a target which is either an actor or an active object method..
+ * Defines an abstract route to a target which is either an actor or an typed actor method..
*
- * @param endpointUri endpoint URI of the consumer actor or active object method.
- * @param id actor identifier or active object identifier (registry key).
+ * @param endpointUri endpoint URI of the consumer actor or typed actor method.
+ * @param id actor identifier or typed actor identifier (registry key).
*
* @author Martin Krasser
*/
@@ -139,31 +139,30 @@ private[camel] abstract class ConsumerRoute(endpointUri: String, id: String) ext
* Defines the route to a consumer actor.
*
* @param endpointUri endpoint URI of the consumer actor
- * @param id actor identifier
- * @param uuid true if id refers to Actor.uuid, false if
- * id refers to Actor.getId.
+ * @param uuid actor uuid
+ * @param blocking true for blocking in-out exchanges, false otherwise
*
* @author Martin Krasser
*/
-private[camel] class ConsumerActorRoute(endpointUri: String, id: String, uuid: Boolean) extends ConsumerRoute(endpointUri, id) {
- protected override def targetUri = (if (uuid) "actor:uuid:%s" else "actor:id:%s") format id
+private[camel] class ConsumerActorRoute(endpointUri: String, uuid: String, blocking: Boolean) extends ConsumerRoute(endpointUri, uuid) {
+ protected override def targetUri = "actor:uuid:%s?blocking=%s" format (uuid, blocking)
}
/**
- * Defines the route to an active object method..
+ * Defines the route to an typed actor method..
*
* @param endpointUri endpoint URI of the consumer actor method
- * @param id active object identifier
+ * @param id typed actor identifier
* @param method name of the method to invoke.
*
* @author Martin Krasser
*/
private[camel] class ConsumerMethodRoute(val endpointUri: String, id: String, method: String) extends ConsumerRoute(endpointUri, id) {
- protected override def targetUri = "%s:%s?method=%s" format (ActiveObjectComponent.InternalSchema, id, method)
+ protected override def targetUri = "%s:%s?method=%s" format (TypedActorComponent.InternalSchema, id, method)
}
/**
- * A registration listener that triggers publication of consumer actors and active object
+ * A registration listener that triggers publication of consumer actors and typed actor
* methods as well as un-publication of consumer actors. This actor needs to be initialized
* with a PublishRequestorInit command message for obtaining a reference to
* a publisher actor. Before initialization it buffers all outbound messages
@@ -210,7 +209,7 @@ private[camel] class PublishRequestor extends Actor {
/**
* Command message to initialize a PublishRequestor to use consumerPublisher
- * for publishing actors or active object methods.
+ * for publishing actors or typed actor methods.
*/
private[camel] case class PublishRequestorInit(consumerPublisher: ActorRef)
@@ -226,54 +225,51 @@ private[camel] sealed trait ConsumerEvent
*
* @param actorRef actor reference
* @param uri endpoint URI of the consumer actor
- * @param id actor identifier
- * @param uuid true if id is the actor's uuid, false if
- * id is the actor's id.
+ * @param uuid actor uuid
+ * @param blocking true for blocking in-out exchanges, false otherwise
*
* @author Martin Krasser
*/
-private[camel] case class ConsumerRegistered(actorRef: ActorRef, uri: String, id: String, uuid: Boolean) extends ConsumerEvent
+private[camel] case class ConsumerRegistered(actorRef: ActorRef, uri: String, uuid: String, blocking: Boolean) extends ConsumerEvent
/**
* Event indicating that a consumer actor has been unregistered from the actor registry.
*
* @param actorRef actor reference
* @param uri endpoint URI of the consumer actor
- * @param id actor identifier
- * @param uuid true if id is the actor's uuid, false if
- * id is the actor's id.
+ * @param uuid actor uuid
*
* @author Martin Krasser
*/
-private[camel] case class ConsumerUnregistered(actorRef: ActorRef, uri: String, id: String, uuid: Boolean) extends ConsumerEvent
+private[camel] case class ConsumerUnregistered(actorRef: ActorRef, uri: String, uuid: String) extends ConsumerEvent
/**
- * Event indicating that an active object proxy has been created for a POJO. For each
+ * Event indicating that an typed actor proxy has been created for a POJO. For each
* @consume annotated POJO method a separate instance of this class is
* created.
*
- * @param activeObject active object (proxy).
+ * @param typedActor typed actor (proxy).
* @param init
- * @param uri endpoint URI of the active object method
+ * @param uri endpoint URI of the typed actor method
* @param method method to be published.
*
* @author Martin Krasser
*/
-private[camel] case class ConsumerMethodRegistered(activeObject: AnyRef, init: AspectInit, uri: String, method: Method) extends ConsumerEvent
+private[camel] case class ConsumerMethodRegistered(typedActor: AnyRef, init: AspectInit, uri: String, method: Method) extends ConsumerEvent
/**
- * Event indicating that an active object has been stopped. For each
+ * Event indicating that an typed actor has been stopped. For each
* @consume annotated POJO method a separate instance of this class is
* created.
*
- * @param activeObject active object (proxy).
+ * @param typedActor typed actor (proxy).
* @param init
- * @param uri endpoint URI of the active object method
+ * @param uri endpoint URI of the typed actor method
* @param method method to be un-published.
*
* @author Martin Krasser
*/
-private[camel] case class ConsumerMethodUnregistered(activeObject: AnyRef, init: AspectInit, uri: String, method: Method) extends ConsumerEvent
+private[camel] case class ConsumerMethodUnregistered(typedActor: AnyRef, init: AspectInit, uri: String, method: Method) extends ConsumerEvent
/**
* @author Martin Krasser
@@ -283,9 +279,10 @@ private[camel] object ConsumerRegistered {
* Optionally creates an ConsumerRegistered event message for a consumer actor or None if
* actorRef is not a consumer actor.
*/
- def forConsumer(actorRef: ActorRef): Option[ConsumerRegistered] = actorRef match {
- case ConsumerDescriptor(ref, uri, id, uuid) => Some(ConsumerRegistered(ref, uri, id, uuid))
- case _ => None
+ def forConsumer(actorRef: ActorRef): Option[ConsumerRegistered] = {
+ Consumer.forConsumer[ConsumerRegistered](actorRef) {
+ target => ConsumerRegistered(actorRef, target.endpointUri, actorRef.uuid, target.blocking)
+ }
}
}
@@ -297,9 +294,10 @@ private[camel] object ConsumerUnregistered {
* Optionally creates an ConsumerUnregistered event message for a consumer actor or None if
* actorRef is not a consumer actor.
*/
- def forConsumer(actorRef: ActorRef): Option[ConsumerUnregistered] = actorRef match {
- case ConsumerDescriptor(ref, uri, id, uuid) => Some(ConsumerUnregistered(ref, uri, id, uuid))
- case _ => None
+ def forConsumer(actorRef: ActorRef): Option[ConsumerUnregistered] = {
+ Consumer.forConsumer[ConsumerUnregistered](actorRef) {
+ target => ConsumerUnregistered(actorRef, target.endpointUri, actorRef.uuid)
+ }
}
}
@@ -308,17 +306,17 @@ private[camel] object ConsumerUnregistered {
*/
private[camel] object ConsumerMethod {
/**
- * Applies a function f to each consumer method of activeObject and
+ * Applies a function f to each consumer method of typedActor and
* returns the function results as a list. A consumer method is one that is annotated with
- * @consume. If activeObject is a proxy for a remote active object
+ * @consume. If typedActor is a proxy for a remote typed actor
* f is never called and Nil is returned.
*/
- def forConsumer[T](activeObject: AnyRef, init: AspectInit)(f: Method => T): List[T] = {
+ def forConsumer[T](typedActor: AnyRef, init: AspectInit)(f: Method => T): List[T] = {
// TODO: support consumer annotation inheritance
// - visit overridden methods in superclasses
// - visit implemented method declarations in interfaces
- if (init.remoteAddress.isDefined) Nil // let remote node publish active object methods on endpoints
- else for (m <- activeObject.getClass.getMethods.toList; if (m.isAnnotationPresent(classOf[consume])))
+ if (init.remoteAddress.isDefined) Nil // let remote node publish typed actor methods on endpoints
+ else for (m <- typedActor.getClass.getMethods.toList; if (m.isAnnotationPresent(classOf[consume])))
yield f(m)
}
}
@@ -328,56 +326,29 @@ private[camel] object ConsumerMethod {
*/
private[camel] object ConsumerMethodRegistered {
/**
- * Creates a list of ConsumerMethodRegistered event messages for an active object or an empty
- * list if the active object is a proxy for an remote active object or the active object doesn't
+ * Creates a list of ConsumerMethodRegistered event messages for an typed actor or an empty
+ * list if the typed actor is a proxy for an remote typed actor or the typed actor doesn't
* have any @consume annotated methods.
*/
- def forConsumer(activeObject: AnyRef, init: AspectInit): List[ConsumerMethodRegistered] = {
- ConsumerMethod.forConsumer[ConsumerMethodRegistered](activeObject, init) {
- m => ConsumerMethodRegistered(activeObject, init, m.getAnnotation(classOf[consume]).value, m)
- }
- }
-}
-
-private[camel] object ConsumerMethodUnregistered {
- /**
- * Creates a list of ConsumerMethodUnregistered event messages for an active object or an empty
- * list if the active object is a proxy for an remote active object or the active object doesn't
- * have any @consume annotated methods.
- */
- def forConsumer(activeObject: AnyRef, init: AspectInit): List[ConsumerMethodUnregistered] = {
- ConsumerMethod.forConsumer[ConsumerMethodUnregistered](activeObject, init) {
- m => ConsumerMethodUnregistered(activeObject, init, m.getAnnotation(classOf[consume]).value, m)
+ def forConsumer(typedActor: AnyRef, init: AspectInit): List[ConsumerMethodRegistered] = {
+ ConsumerMethod.forConsumer(typedActor, init) {
+ m => ConsumerMethodRegistered(typedActor, init, m.getAnnotation(classOf[consume]).value, m)
}
}
}
/**
- * Describes a consumer actor with elements that are relevant for publishing an actor at a
- * Camel endpoint (or unpublishing an actor from an endpoint).
- *
* @author Martin Krasser
*/
-private[camel] object ConsumerDescriptor {
-
+private[camel] object ConsumerMethodUnregistered {
/**
- * An extractor that optionally creates a 4-tuple from a consumer actor reference containing
- * the actor reference itself, endpoint URI, identifier and a hint whether the identifier
- * is the actor uuid or actor id. If actorRef doesn't reference a consumer actor,
- * None is returned.
+ * Creates a list of ConsumerMethodUnregistered event messages for an typed actor or an empty
+ * list if the typed actor is a proxy for an remote typed actor or the typed actor doesn't
+ * have any @consume annotated methods.
*/
- def unapply(actorRef: ActorRef): Option[(ActorRef, String, String, Boolean)] =
- unapplyConsumerInstance(actorRef) orElse unapplyConsumeAnnotated(actorRef)
-
- private def unapplyConsumeAnnotated(actorRef: ActorRef): Option[(ActorRef, String, String, Boolean)] = {
- val annotation = actorRef.actorClass.getAnnotation(classOf[consume])
- if (annotation eq null) None
- else if (actorRef.remoteAddress.isDefined) None
- else Some((actorRef, annotation.value, actorRef.id, false))
+ def forConsumer(typedActor: AnyRef, init: AspectInit): List[ConsumerMethodUnregistered] = {
+ ConsumerMethod.forConsumer(typedActor, init) {
+ m => ConsumerMethodUnregistered(typedActor, init, m.getAnnotation(classOf[consume]).value, m)
+ }
}
-
- private def unapplyConsumerInstance(actorRef: ActorRef): Option[(ActorRef, String, String, Boolean)] =
- if (!actorRef.actor.isInstanceOf[Consumer]) None
- else if (actorRef.remoteAddress.isDefined) None
- else Some((actorRef, actorRef.actor.asInstanceOf[Consumer].endpointUri, actorRef.uuid, true))
}
diff --git a/akka-camel/src/main/scala/Producer.scala b/akka-camel/src/main/scala/Producer.scala
index 9a68b8d57f..c49591ec7f 100644
--- a/akka-camel/src/main/scala/Producer.scala
+++ b/akka-camel/src/main/scala/Producer.scala
@@ -6,13 +6,10 @@ package se.scalablesolutions.akka.camel
import CamelMessageConversion.toExchangeAdapter
-import org.apache.camel.{Processor, ExchangePattern, Exchange, ProducerTemplate}
-import org.apache.camel.impl.DefaultExchange
-import org.apache.camel.spi.Synchronization
+import org.apache.camel._
+import org.apache.camel.processor.SendProcessor
import se.scalablesolutions.akka.actor.{Actor, ActorRef}
-import se.scalablesolutions.akka.dispatch.CompletableFuture
-import se.scalablesolutions.akka.util.Logging
/**
* Mixed in by Actor implementations that produce messages to Camel endpoints.
@@ -21,15 +18,21 @@ import se.scalablesolutions.akka.util.Logging
*/
trait Producer { this: Actor =>
+ /**
+ * Message headers to copy by default from request message to response-message.
+ */
private val headersToCopyDefault = Set(Message.MessageExchangeId)
/**
- * If set to true (default), communication with the Camel endpoint is done via the Camel
- * Async API. Camel then processes the
- * message in a separate thread. If set to false, the actor thread is blocked until Camel
- * has finished processing the produced message.
+ * Endpoint object resolved from current CamelContext with
+ * endpointUri.
*/
- def async: Boolean = true
+ private lazy val endpoint = CamelContextManager.context.getEndpoint(endpointUri)
+
+ /**
+ * SendProcessor for producing messages to endpoint.
+ */
+ private lazy val processor = createSendProcessor
/**
* If set to false (default), this producer expects a response message from the Camel endpoint.
@@ -51,146 +54,123 @@ trait Producer { this: Actor =>
def headersToCopy: Set[String] = headersToCopyDefault
/**
- * Returns the producer template from the CamelContextManager. Applications either have to ensure
- * proper initialization of CamelContextManager or override this method.
- *
- * @see CamelContextManager.
+ * Default implementation of Actor.shutdown for freeing resources needed
+ * to actually send messages to endpointUri.
*/
- protected def template: ProducerTemplate = CamelContextManager.template
-
- /**
- * Initiates a one-way (in-only) message exchange to the Camel endpoint given by
- * endpointUri. This method blocks until Camel finishes processing
- * the message exchange.
- *
- * @param msg: the message to produce. The message is converted to its canonical
- * representation via Message.canonicalize.
- */
- protected def produceOnewaySync(msg: Any): Unit =
- template.send(endpointUri, createInOnlyExchange.fromRequestMessage(Message.canonicalize(msg)))
-
- /**
- * Initiates a one-way (in-only) message exchange to the Camel endpoint given by
- * endpointUri. This method triggers asynchronous processing of the
- * message exchange by Camel.
- *
- * @param msg: the message to produce. The message is converted to its canonical
- * representation via Message.canonicalize.
- */
- protected def produceOnewayAsync(msg: Any): Unit =
- template.asyncSend(
- endpointUri, createInOnlyExchange.fromRequestMessage(Message.canonicalize(msg)))
-
- /**
- * Initiates a two-way (in-out) message exchange to the Camel endpoint given by
- * endpointUri. This method blocks until Camel finishes processing
- * the message exchange.
- *
- * @param msg: the message to produce. The message is converted to its canonical
- * representation via Message.canonicalize.
- * @return either a response Message or a Failure object.
- */
- protected def produceSync(msg: Any): Any = {
- val cmsg = Message.canonicalize(msg)
- val requestProcessor = new Processor() {
- def process(exchange: Exchange) = exchange.fromRequestMessage(cmsg)
- }
- val result = template.request(endpointUri, requestProcessor)
- if (result.isFailed) result.toFailureMessage(cmsg.headers(headersToCopy))
- else result.toResponseMessage(cmsg.headers(headersToCopy))
+ override def shutdown {
+ processor.stop
}
/**
- * Initiates a two-way (in-out) message exchange to the Camel endpoint given by
- * endpointUri. This method triggers asynchronous processing of the
- * message exchange by Camel. The response message is returned asynchronously to
- * the original sender (or sender future).
+ * Produces msg as exchange of given pattern to the endpoint specified by
+ * endpointUri. After producing to the endpoint the processing result is passed as argument
+ * to receiveAfterProduce. If the result was returned synchronously by the endpoint then
+ * receiveAfterProduce is called synchronously as well. If the result was returned asynchronously,
+ * the receiveAfterProduce is called asynchronously as well. This is done by wrapping the result,
+ * adding it to this producers mailbox, unwrapping it once it is received and calling
+ * receiveAfterProduce. The original sender and senderFuture are thereby preserved.
*
- * @param msg: the message to produce. The message is converted to its canonical
- * representation via Message.canonicalize.
- * @return either a response Message or a Failure object.
- * @see ProducerResponseSender
+ * @param msg message to produce
+ * @param pattern exchange pattern
*/
- protected def produceAsync(msg: Any): Unit = {
+ protected def produce(msg: Any, pattern: ExchangePattern): Unit = {
val cmsg = Message.canonicalize(msg)
- val sync = new ProducerResponseSender(
- cmsg.headers(headersToCopy), self.sender, self.senderFuture, this)
- template.asyncCallback(endpointUri, createInOutExchange.fromRequestMessage(cmsg), sync)
+ val exchange = createExchange(pattern).fromRequestMessage(cmsg)
+ processor.process(exchange, new AsyncCallback {
+ val producer = self
+ // Need copies of sender and senderFuture references here
+ // since the callback could be done later by another thread.
+ val sender = self.sender
+ val senderFuture = self.senderFuture
+
+ def done(doneSync: Boolean): Unit = {
+ (doneSync, exchange.isFailed) match {
+ case (true, true) => dispatchSync(exchange.toFailureMessage(cmsg.headers(headersToCopy)))
+ case (true, false) => dispatchSync(exchange.toResponseMessage(cmsg.headers(headersToCopy)))
+ case (false, true) => dispatchAsync(FailureResult(exchange.toFailureMessage(cmsg.headers(headersToCopy))))
+ case (false, false) => dispatchAsync(MessageResult(exchange.toResponseMessage(cmsg.headers(headersToCopy))))
+ }
+ }
+
+ private def dispatchSync(result: Any) =
+ receiveAfterProduce(result)
+
+ private def dispatchAsync(result: Any) = {
+ if (senderFuture.isDefined)
+ producer.postMessageToMailboxAndCreateFutureResultWithTimeout(result, producer.timeout, sender, senderFuture)
+ else
+ producer.postMessageToMailbox(result, sender)
+ }
+ })
}
/**
- * Default implementation for Actor.receive. Implementors may choose to
- * def receive = produce. This partial function calls one of
- * the protected produce methods depending on the return values of
- * oneway and async.
+ * Produces msg to the endpoint specified by endpointUri. Before the message is
+ * actually produced it is pre-processed by calling receiveBeforeProduce. If oneway
+ * is true an in-only message exchange is initiated, otherwise an in-out message exchange.
+ *
+ * @see Producer#produce(Any, ExchangePattern)
*/
protected def produce: Receive = {
+ case res: MessageResult => receiveAfterProduce(res.message)
+ case res: FailureResult => receiveAfterProduce(res.failure)
case msg => {
- if ( oneway && !async) produceOnewaySync(msg)
- else if ( oneway && async) produceOnewayAsync(msg)
- else if (!oneway && !async) self.reply(produceSync(msg))
- else /*(!oneway && async)*/ produceAsync(msg)
+ if (oneway)
+ produce(receiveBeforeProduce(msg), ExchangePattern.InOnly)
+ else
+ produce(receiveBeforeProduce(msg), ExchangePattern.InOut)
}
}
+ /**
+ * Called before the message is sent to the endpoint specified by endpointUri. The original
+ * message is passed as argument. By default, this method simply returns the argument but may be overridden
+ * by subtraits or subclasses.
+ */
+ protected def receiveBeforeProduce: PartialFunction[Any, Any] = {
+ case msg => msg
+ }
+
+ /**
+ * Called after the a result was received from the endpoint specified by endpointUri. The
+ * result is passed as argument. By default, this method replies the result back to the original sender
+ * if oneway is false. If oneway is true then nothing is done. This method may
+ * be overridden by subtraits or subclasses.
+ */
+ protected def receiveAfterProduce: Receive = {
+ case msg => if (!oneway) self.reply(msg)
+ }
+
/**
* Default implementation of Actor.receive
*/
protected def receive = produce
/**
- * Creates a new in-only Exchange.
+ * Creates a new Exchange with given pattern from the endpoint specified by
+ * endpointUri.
*/
- protected def createInOnlyExchange: Exchange = createExchange(ExchangePattern.InOnly)
+ private def createExchange(pattern: ExchangePattern): Exchange = endpoint.createExchange(pattern)
/**
- * Creates a new in-out Exchange.
+ * Creates a new SendProcessor for endpoint.
*/
- protected def createInOutExchange: Exchange = createExchange(ExchangePattern.InOut)
-
- /**
- * Creates a new Exchange with given pattern from the CamelContext managed by
- * CamelContextManager. Applications either have to ensure proper initialization
- * of CamelContextManager or override this method.
- *
- * @see CamelContextManager.
- */
- protected def createExchange(pattern: ExchangePattern): Exchange =
- new DefaultExchange(CamelContextManager.context, pattern)
+ private def createSendProcessor = {
+ val sendProcessor = new SendProcessor(endpoint)
+ sendProcessor.start
+ sendProcessor
+ }
}
/**
- * Synchronization object that sends responses asynchronously to initial senders. This
- * class is used by Producer for asynchronous two-way messaging with a Camel endpoint.
- *
* @author Martin Krasser
*/
-private[camel] class ProducerResponseSender(
- headers: Map[String, Any],
- sender: Option[ActorRef],
- senderFuture: Option[CompletableFuture[Any]],
- producer: Actor) extends Synchronization with Logging {
+private[camel] case class MessageResult(message: Message)
- implicit val producerActor = Some(producer) // the response sender
-
- /**
- * Replies a Failure message, created from the given exchange, to sender (or
- * senderFuture if applicable).
- */
- def onFailure(exchange: Exchange) = reply(exchange.toFailureMessage(headers))
-
- /**
- * Replies a response Message, created from the given exchange, to sender (or
- * senderFuture if applicable).
- */
- def onComplete(exchange: Exchange) = reply(exchange.toResponseMessage(headers))
-
- private def reply(message: Any) = {
- if (senderFuture.isDefined) senderFuture.get completeWithResult message
- else if (sender.isDefined) sender.get ! message
- else log.warning("No destination for sending response")
- }
-}
+/**
+ * @author Martin Krasser
+ */
+private[camel] case class FailureResult(failure: Failure)
/**
* A one-way producer.
@@ -201,12 +181,3 @@ trait Oneway extends Producer { this: Actor =>
override def oneway = true
}
-/**
- * A synchronous producer.
- *
- * @author Martin Krasser
- */
-trait Sync extends Producer { this: Actor =>
- override def async = false
-}
-
diff --git a/akka-camel/src/main/scala/component/ActorComponent.scala b/akka-camel/src/main/scala/component/ActorComponent.scala
index e80595515e..1cd29ced00 100644
--- a/akka-camel/src/main/scala/component/ActorComponent.scala
+++ b/akka-camel/src/main/scala/component/ActorComponent.scala
@@ -4,15 +4,25 @@
package se.scalablesolutions.akka.camel.component
-import java.lang.{RuntimeException, String}
+import java.net.InetSocketAddress
import java.util.{Map => JavaMap}
import java.util.concurrent.TimeoutException
+import java.util.concurrent.atomic.AtomicReference
-import org.apache.camel.{Exchange, Consumer, Processor}
+import jsr166x.Deque
+
+import org.apache.camel._
import org.apache.camel.impl.{DefaultProducer, DefaultEndpoint, DefaultComponent}
import se.scalablesolutions.akka.actor.{ActorRegistry, Actor, ActorRef}
import se.scalablesolutions.akka.camel.{Failure, CamelMessageConversion, Message}
+import se.scalablesolutions.akka.dispatch.{CompletableFuture, MessageInvocation, MessageDispatcher}
+import se.scalablesolutions.akka.stm.TransactionConfig
+
+import scala.reflect.BeanProperty
+
+import CamelMessageConversion.toExchangeAdapter
+import java.lang.Throwable
/**
* Camel component for sending messages to and receiving replies from actors.
@@ -41,7 +51,7 @@ class ActorComponent extends DefaultComponent {
/**
* Camel endpoint for referencing an actor. The actor reference is given by the endpoint URI.
- * An actor can be referenced by its Actor.getId or its Actor.uuid.
+ * An actor can be referenced by its ActorRef.id or its ActorRef.uuid.
* Supported endpoint URI formats are
* actor:<actorid>,
* actor:id:<actorid> and
@@ -57,6 +67,12 @@ class ActorEndpoint(uri: String,
val id: Option[String],
val uuid: Option[String]) extends DefaultEndpoint(uri, comp) {
+ /**
+ * Blocking of client thread during two-way message exchanges with consumer actors. This is set
+ * via the blocking=true|false endpoint URI parameter. If omitted blocking is false.
+ */
+ @BeanProperty var blocking: Boolean = false
+
/**
* @throws UnsupportedOperationException
*/
@@ -75,60 +91,59 @@ class ActorEndpoint(uri: String,
}
/**
- * Sends the in-message of an exchange to an actor. If the exchange pattern is out-capable,
- * the producer waits for a reply (using the !! operator), otherwise the ! operator is used
- * for sending the message.
+ * Sends the in-message of an exchange to an actor. If the exchange pattern is out-capable and
+ * blocking is enabled then the producer waits for a reply (using the !! operator),
+ * otherwise the ! operator is used for sending the message.
*
* @see se.scalablesolutions.akka.camel.component.ActorComponent
* @see se.scalablesolutions.akka.camel.component.ActorEndpoint
*
* @author Martin Krasser
*/
-class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) {
- import CamelMessageConversion.toExchangeAdapter
+class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) with AsyncProcessor {
+ import ActorProducer._
- implicit val sender = None
+ def process(exchange: Exchange) =
+ if (exchange.getPattern.isOutCapable) sendSync(exchange) else sendAsync(exchange)
- /**
- * Depending on the exchange pattern, this method either calls processInOut or
- * processInOnly for interacting with an actor. This methods looks up the actor
- * from the ActorRegistry according to this producer's endpoint URI.
- *
- * @param exchange represents the message exchange with the actor.
- */
- def process(exchange: Exchange) {
- val actor = target getOrElse (throw new ActorNotRegisteredException(ep.getEndpointUri))
- if (exchange.getPattern.isOutCapable) processInOut(exchange, actor)
- else processInOnly(exchange, actor)
- }
-
- /**
- * 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.
- */
- protected def processInOnly(exchange: Exchange, actor: ActorRef): Unit =
- actor ! exchange.toRequestMessage(Map(Message.MessageExchangeId -> exchange.getExchangeId))
-
- /**
- * Send the exchange in-message to the given actor using the !! operator. The exchange
- * out-message is populated from the actor's reply message. The message sent to the
- * actor is of type se.scalablesolutions.akka.camel.Message.
- */
- protected def processInOut(exchange: Exchange, actor: ActorRef) {
- val header = Map(Message.MessageExchangeId -> exchange.getExchangeId)
- val result: Any = actor !! exchange.toRequestMessage(header)
-
- result match {
- case Some(msg: Failure) => exchange.fromFailureMessage(msg)
- case Some(msg) => exchange.fromResponseMessage(Message.canonicalize(msg))
- case None => {
- throw new TimeoutException("timeout (%d ms) while waiting response from %s"
- format (actor.timeout, ep.getEndpointUri))
+ def process(exchange: Exchange, callback: AsyncCallback): Boolean = {
+ (exchange.getPattern.isOutCapable, ep.blocking) match {
+ case (true, true) => {
+ sendSync(exchange)
+ callback.done(true)
+ true
+ }
+ case (true, false) => {
+ sendAsync(exchange, Some(AsyncCallbackAdapter(exchange, callback)))
+ false
+ }
+ case (false, _) => {
+ sendAsync(exchange)
+ callback.done(true)
+ true
}
}
}
- private def target: Option[ActorRef] =
+ private def sendSync(exchange: Exchange) = {
+ val actor = target
+ val result: Any = actor !! requestFor(exchange)
+
+ result match {
+ case Some(msg: Failure) => exchange.fromFailureMessage(msg)
+ case Some(msg) => exchange.fromResponseMessage(Message.canonicalize(msg))
+ case None => throw new TimeoutException("timeout (%d ms) while waiting response from %s"
+ format (actor.timeout, ep.getEndpointUri))
+ }
+ }
+
+ private def sendAsync(exchange: Exchange, sender: Option[ActorRef] = None) =
+ target.!(requestFor(exchange))(sender)
+
+ private def target =
+ targetOption getOrElse (throw new ActorNotRegisteredException(ep.getEndpointUri))
+
+ private def targetOption: Option[ActorRef] =
if (ep.id.isDefined) targetById(ep.id.get)
else targetByUuid(ep.uuid.get)
@@ -141,6 +156,14 @@ class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) {
private def targetByUuid(uuid: String) = ActorRegistry.actorFor(uuid)
}
+/**
+ * @author Martin Krasser
+ */
+private[camel] object ActorProducer {
+ def requestFor(exchange: Exchange) =
+ exchange.toRequestMessage(Map(Message.MessageExchangeId -> exchange.getExchangeId))
+}
+
/**
* Thrown to indicate that an actor referenced by an endpoint URI cannot be
* found in the ActorRegistry.
@@ -150,3 +173,92 @@ class ActorProducer(val ep: ActorEndpoint) extends DefaultProducer(ep) {
class ActorNotRegisteredException(uri: String) extends RuntimeException {
override def getMessage = "%s not registered" format uri
}
+
+/**
+ * @author Martin Krasser
+ */
+private[akka] object AsyncCallbackAdapter {
+ /**
+ * Creates and starts an AsyncCallbackAdapter.
+ *
+ * @param exchange message exchange to write results to.
+ * @param callback callback object to generate completion notifications.
+ */
+ def apply(exchange: Exchange, callback: AsyncCallback) =
+ new AsyncCallbackAdapter(exchange, callback).start
+}
+
+/**
+ * Adapts an AsyncCallback to ActorRef.!. Used by other actors to reply
+ * asynchronously to Camel with ActorRef.reply.
+ *
+ * Please note that this adapter can only be used locally at the moment which should not
+ * be a problem is most situations as Camel endpoints are only activated for local actor references,
+ * never for remote references.
+ *
+ * @author Martin Krasser
+ */
+private[akka] class AsyncCallbackAdapter(exchange: Exchange, callback: AsyncCallback) extends ActorRef {
+
+ def start = {
+ _isRunning = true
+ this
+ }
+
+ def stop() = {
+ _isRunning = false
+ _isShutDown = true
+ }
+
+ /**
+ * Writes the reply message to exchange and uses callback to
+ * generate completion notifications.
+ *
+ * @param message reply message
+ * @param sender ignored
+ */
+ protected[akka] def postMessageToMailbox(message: Any, senderOption: Option[ActorRef]) = {
+ message match {
+ case msg: Failure => exchange.fromFailureMessage(msg)
+ case msg => exchange.fromResponseMessage(Message.canonicalize(msg))
+ }
+ callback.done(false)
+ }
+
+ def actorClass: Class[_ <: Actor] = unsupported
+ def actorClassName = unsupported
+ def dispatcher_=(md: MessageDispatcher): Unit = unsupported
+ def dispatcher: MessageDispatcher = unsupported
+ def transactionConfig_=(config: TransactionConfig): Unit = unsupported
+ def transactionConfig: TransactionConfig = unsupported
+ def makeTransactionRequired: Unit = unsupported
+ def makeRemote(hostname: String, port: Int): Unit = unsupported
+ def makeRemote(address: InetSocketAddress): Unit = unsupported
+ def homeAddress_=(address: InetSocketAddress): Unit = unsupported
+ def remoteAddress: Option[InetSocketAddress] = unsupported
+ def link(actorRef: ActorRef): Unit = unsupported
+ def unlink(actorRef: ActorRef): Unit = unsupported
+ def startLink(actorRef: ActorRef): Unit = unsupported
+ def startLinkRemote(actorRef: ActorRef, hostname: String, port: Int): Unit = unsupported
+ def spawn[T <: Actor : Manifest]: ActorRef = unsupported
+ def spawnRemote[T <: Actor: Manifest](hostname: String, port: Int): ActorRef = unsupported
+ def spawnLink[T <: Actor: Manifest]: ActorRef = unsupported
+ def spawnLinkRemote[T <: Actor : Manifest](hostname: String, port: Int): ActorRef = unsupported
+ def shutdownLinkedActors: Unit = unsupported
+ def supervisor: Option[ActorRef] = unsupported
+ protected[akka] def postMessageToMailboxAndCreateFutureResultWithTimeout[T](message: Any, timeout: Long, senderOption: Option[ActorRef], senderFuture: Option[CompletableFuture[T]]) = unsupported
+ protected[akka] def mailbox: AnyRef = unsupported
+ protected[akka] def mailbox_=(msg: AnyRef):AnyRef = unsupported
+ protected[akka] def restart(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit = unsupported
+ protected[akka] def restartLinkedActors(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit = unsupported
+ protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit = unsupported
+ protected[akka] def linkedActors: JavaMap[String, ActorRef] = unsupported
+ protected[akka] def linkedActorsAsList: List[ActorRef] = unsupported
+ protected[akka] def invoke(messageHandle: MessageInvocation): Unit = unsupported
+ protected[akka] def remoteAddress_=(addr: Option[InetSocketAddress]): Unit = unsupported
+ protected[akka] def registerSupervisorAsRemoteActor = unsupported
+ protected[akka] def supervisor_=(sup: Option[ActorRef]): Unit = unsupported
+ protected[this] def actorInstance: AtomicReference[Actor] = unsupported
+
+ private def unsupported = throw new UnsupportedOperationException("Not supported for %s" format classOf[AsyncCallbackAdapter].getName)
+}
diff --git a/akka-camel/src/main/scala/component/ActiveObjectComponent.scala b/akka-camel/src/main/scala/component/TypedActorComponent.scala
similarity index 64%
rename from akka-camel/src/main/scala/component/ActiveObjectComponent.scala
rename to akka-camel/src/main/scala/component/TypedActorComponent.scala
index 05fa026e04..2a48cf9fc4 100644
--- a/akka-camel/src/main/scala/component/ActiveObjectComponent.scala
+++ b/akka-camel/src/main/scala/component/TypedActorComponent.scala
@@ -12,31 +12,31 @@ import org.apache.camel.component.bean._
/**
* @author Martin Krasser
*/
-object ActiveObjectComponent {
+object TypedActorComponent {
/**
- * Default schema name for active object endpoint URIs.
+ * Default schema name for typed actor endpoint URIs.
*/
- val InternalSchema = "active-object-internal"
+ val InternalSchema = "typed-actor-internal"
}
/**
- * Camel component for exchanging messages with active objects. This component
- * tries to obtain the active object from the activeObjectRegistry
+ * Camel component for exchanging messages with typed actors. This component
+ * tries to obtain the typed actor from the typedActorRegistry
* first. If it's not there it tries to obtain it from the CamelContext's registry.
*
* @see org.apache.camel.component.bean.BeanComponent
*
* @author Martin Krasser
*/
-class ActiveObjectComponent extends BeanComponent {
- val activeObjectRegistry = new ConcurrentHashMap[String, AnyRef]
+class TypedActorComponent extends BeanComponent {
+ val typedActorRegistry = new ConcurrentHashMap[String, AnyRef]
/**
* Creates a {@link org.apache.camel.component.bean.BeanEndpoint} with a custom
- * bean holder that uses activeObjectRegistry for getting access to
- * active objects (beans).
+ * bean holder that uses typedActorRegistry for getting access to
+ * typed actors (beans).
*
- * @see se.scalablesolutions.akka.camel.component.ActiveObjectHolder
+ * @see se.scalablesolutions.akka.camel.component.TypedActorHolder
*/
override def createEndpoint(uri: String, remaining: String, parameters: Map[String, AnyRef]) = {
val endpoint = new BeanEndpoint(uri, this)
@@ -47,39 +47,39 @@ class ActiveObjectComponent extends BeanComponent {
}
private def createBeanHolder(beanName: String) =
- new ActiveObjectHolder(activeObjectRegistry, getCamelContext, beanName).createCacheHolder
+ new TypedActorHolder(typedActorRegistry, getCamelContext, beanName).createCacheHolder
}
/**
* {@link org.apache.camel.component.bean.BeanHolder} implementation that uses a custom
- * registry for getting access to active objects.
+ * registry for getting access to typed actors.
*
* @author Martin Krasser
*/
-class ActiveObjectHolder(activeObjectRegistry: Map[String, AnyRef], context: CamelContext, name: String)
+class TypedActorHolder(typedActorRegistry: Map[String, AnyRef], context: CamelContext, name: String)
extends RegistryBean(context, name) {
/**
- * Returns an {@link se.scalablesolutions.akka.camel.component.ActiveObjectInfo} instance.
+ * Returns an {@link se.scalablesolutions.akka.camel.component.TypedActorInfo} instance.
*/
override def getBeanInfo: BeanInfo =
- new ActiveObjectInfo(getContext, getBean.getClass, getParameterMappingStrategy)
+ new TypedActorInfo(getContext, getBean.getClass, getParameterMappingStrategy)
/**
- * Obtains an active object from activeObjectRegistry.
+ * Obtains an typed actor from typedActorRegistry.
*/
override def getBean: AnyRef = {
- val bean = activeObjectRegistry.get(getName)
+ val bean = typedActorRegistry.get(getName)
if (bean eq null) super.getBean else bean
}
}
/**
- * Provides active object meta information.
+ * Provides typed actor meta information.
*
* @author Martin Krasser
*/
-class ActiveObjectInfo(context: CamelContext, clazz: Class[_], strategy: ParameterMappingStrategy)
+class TypedActorInfo(context: CamelContext, clazz: Class[_], strategy: ParameterMappingStrategy)
extends BeanInfo(context, clazz, strategy) {
/**
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBase.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBase.java
index 05bf1625bb..f0f0b8ee4d 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBase.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBase.java
@@ -1,34 +1,28 @@
package se.scalablesolutions.akka.camel;
-import org.apache.camel.Body;
-import org.apache.camel.Header;
-
-import se.scalablesolutions.akka.actor.annotation.consume;
+import se.scalablesolutions.akka.actor.TypedActor;
/**
* @author Martin Krasser
*/
-public class PojoBase {
+public class PojoBase extends TypedActor implements PojoBaseIntf {
public String m1(String b, String h) {
return "m1base: " + b + " " + h;
}
- @consume("direct:m2base")
- public String m2(@Body String b, @Header("test") String h) {
+ public String m2(String b, String h) {
return "m2base: " + b + " " + h;
}
- @consume("direct:m3base")
- public String m3(@Body String b, @Header("test") String h) {
+ public String m3(String b, String h) {
return "m3base: " + b + " " + h;
}
- @consume("direct:m4base")
- public String m4(@Body String b, @Header("test") String h) {
+ public String m4(String b, String h) {
return "m4base: " + b + " " + h;
}
- public void m5(@Body String b, @Header("test") String h) {
+ public void m5(String b, String h) {
}
}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBaseIntf.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBaseIntf.java
new file mode 100644
index 0000000000..2ca8ef4360
--- /dev/null
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoBaseIntf.java
@@ -0,0 +1,21 @@
+package se.scalablesolutions.akka.camel;
+
+import org.apache.camel.Body;
+import org.apache.camel.Header;
+
+import se.scalablesolutions.akka.actor.annotation.consume;
+
+/**
+ * @author Martin Krasser
+ */
+public interface PojoBaseIntf {
+
+ public String m1(String b, String h);
+ @consume("direct:m2base")
+ public String m2(@Body String b, @Header("test") String h);
+ @consume("direct:m3base")
+ public String m3(@Body String b, @Header("test") String h);
+ @consume("direct:m4base")
+ public String m4(@Body String b, @Header("test") String h);
+ public void m5(@Body String b, @Header("test") String h);
+}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoImpl.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoImpl.java
index b48202d4dc..f8ade8ac97 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoImpl.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoImpl.java
@@ -1,23 +1,17 @@
package se.scalablesolutions.akka.camel;
-import org.apache.camel.Body;
-import org.apache.camel.Header;
-
-import se.scalablesolutions.akka.actor.annotation.consume;
+import se.scalablesolutions.akka.actor.TypedActor;
/**
* @author Martin Krasser
*/
-public class PojoImpl implements PojoIntf {
+public class PojoImpl extends TypedActor implements PojoIntf {
public String m1(String b, String h) {
return "m1impl: " + b + " " + h;
}
- @consume("direct:m2impl")
- public String m2(@Body String b, @Header("test") String h) {
+ public String m2(String b, String h) {
return "m2impl: " + b + " " + h;
}
-
-
}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/Pojo.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoNonConsumer.java
similarity index 57%
rename from akka-camel/src/test/java/se/scalablesolutions/akka/camel/Pojo.java
rename to akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoNonConsumer.java
index d1848c49ee..fc6ea834fd 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/Pojo.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoNonConsumer.java
@@ -1,11 +1,11 @@
package se.scalablesolutions.akka.camel;
-import se.scalablesolutions.akka.actor.annotation.consume;
+import se.scalablesolutions.akka.actor.*;
/**
* @author Martin Krasser
*/
-public class Pojo {
+public class PojoNonConsumer extends TypedActor implements PojoNonConsumerIntf {
public String foo(String s) {
return String.format("foo: %s", s);
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoNonConsumerIntf.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoNonConsumerIntf.java
new file mode 100644
index 0000000000..aec8caaf19
--- /dev/null
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoNonConsumerIntf.java
@@ -0,0 +1,9 @@
+package se.scalablesolutions.akka.camel;
+
+/**
+ * @author Martin Krasser
+ */
+public interface PojoNonConsumerIntf {
+
+ public String foo(String s);
+}
\ No newline at end of file
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemote.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemote.java
index 57b0999b8f..3ea8b05180 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemote.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemote.java
@@ -1,15 +1,14 @@
package se.scalablesolutions.akka.camel;
-import se.scalablesolutions.akka.actor.annotation.consume;
+import se.scalablesolutions.akka.actor.TypedActor;
/**
* @author Martin Krasser
*/
-public class PojoRemote {
+public class PojoRemote extends TypedActor implements PojoRemoteIntf {
- @consume("direct:remote-active-object")
public String foo(String s) {
- return String.format("remote active object: %s", s);
+ return String.format("remote typed actor: %s", s);
}
}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemoteIntf.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemoteIntf.java
new file mode 100644
index 0000000000..45f09e1757
--- /dev/null
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoRemoteIntf.java
@@ -0,0 +1,12 @@
+package se.scalablesolutions.akka.camel;
+
+import se.scalablesolutions.akka.actor.annotation.consume;
+
+/**
+ * @author Martin Krasser
+ */
+public interface PojoRemoteIntf {
+
+ @consume("direct:remote-typed-actor")
+ public String foo(String s);
+}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingle.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingle.java
index 7d577535b2..7d4f6be5da 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingle.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingle.java
@@ -1,13 +1,12 @@
package se.scalablesolutions.akka.camel;
-import se.scalablesolutions.akka.actor.annotation.consume;
+import se.scalablesolutions.akka.actor.TypedActor;
/**
* @author Martin Krasser
*/
-public class PojoSingle {
+public class PojoSingle extends TypedActor implements PojoSingleIntf {
- @consume("direct:foo")
public void foo(String b) {
}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingleIntf.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingleIntf.java
new file mode 100644
index 0000000000..22a25325a3
--- /dev/null
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSingleIntf.java
@@ -0,0 +1,12 @@
+package se.scalablesolutions.akka.camel;
+
+import se.scalablesolutions.akka.actor.annotation.consume;
+
+/**
+ * @author Martin Krasser
+ */
+public interface PojoSingleIntf {
+
+ @consume("direct:foo")
+ public void foo(String b);
+}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSub.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSub.java
index be5b453698..a7e592ef01 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSub.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSub.java
@@ -1,15 +1,11 @@
package se.scalablesolutions.akka.camel;
-import org.apache.camel.Body;
-import org.apache.camel.Header;
+import se.scalablesolutions.akka.actor.TypedActor;
-import se.scalablesolutions.akka.actor.annotation.consume;
-
-public class PojoSub extends PojoBase {
+public class PojoSub extends PojoBase implements PojoSubIntf {
@Override
- @consume("direct:m1sub")
- public String m1(@Body String b, @Header("test") String h) {
+ public String m1(String b, String h) {
return "m1sub: " + b + " " + h;
}
@@ -19,8 +15,7 @@ public class PojoSub extends PojoBase {
}
@Override
- @consume("direct:m3sub")
- public String m3(@Body String b, @Header("test") String h) {
+ public String m3(String b, String h) {
return "m3sub: " + b + " " + h;
}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSubIntf.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSubIntf.java
new file mode 100644
index 0000000000..08a153b124
--- /dev/null
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/PojoSubIntf.java
@@ -0,0 +1,18 @@
+package se.scalablesolutions.akka.camel;
+
+import org.apache.camel.Body;
+import org.apache.camel.Header;
+
+import se.scalablesolutions.akka.actor.annotation.consume;
+
+public interface PojoSubIntf extends PojoBaseIntf {
+ @consume("direct:m1sub")
+ public String m1(@Body String b, @Header("test") String h);
+
+ @Override
+ public String m2(String b, String h);
+
+ @Override
+ @consume("direct:m3sub")
+ public String m3(@Body String b, @Header("test") String h);
+}
diff --git a/akka-camel/src/test/scala/CamelServiceFeatureTest.scala b/akka-camel/src/test/scala/CamelServiceFeatureTest.scala
index 1e88b62bf2..71ab86599d 100644
--- a/akka-camel/src/test/scala/CamelServiceFeatureTest.scala
+++ b/akka-camel/src/test/scala/CamelServiceFeatureTest.scala
@@ -1,12 +1,13 @@
package se.scalablesolutions.akka.camel
-import java.util.concurrent.{CountDownLatch, TimeUnit}
+import java.util.concurrent.{TimeoutException, CountDownLatch, TimeUnit}
+import org.apache.camel.CamelExecutionException
import org.apache.camel.builder.RouteBuilder
import org.scalatest.{GivenWhenThen, BeforeAndAfterAll, FeatureSpec}
import se.scalablesolutions.akka.actor.Actor._
-import se.scalablesolutions.akka.actor.{ActiveObject, Actor, ActorRegistry}
+import se.scalablesolutions.akka.actor.{TypedActor, Actor, ActorRegistry}
class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with GivenWhenThen {
import CamelServiceFeatureTest._
@@ -16,7 +17,7 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
override protected def beforeAll = {
ActorRegistry.shutdownAll
// create new CamelService instance
- service = CamelService.newInstance
+ service = CamelServiceFactory.createCamelService
// register test consumer before starting the CamelService
actorOf(new TestConsumer("direct:publish-test-1")).start
// Configure a custom camel route
@@ -26,7 +27,7 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
// count expectations in the next step (needed for testing only).
service.consumerPublisher.start
// set expectations on publish count
- val latch = (service.consumerPublisher !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ val latch = service.expectEndpointActivationCount(1)
// start the CamelService
service.load
// await publication of first test consumer
@@ -40,10 +41,10 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
feature("Publish registered consumer actors in the global CamelContext") {
- scenario("access registered consumer actors via Camel direct-endpoints") {
+ scenario("access non-blocking consumer actors via Camel direct-endpoints") {
given("two consumer actors registered before and after CamelService startup")
- val latch = (service.consumerPublisher !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ val latch = service.expectEndpointActivationCount(1)
actorOf(new TestConsumer("direct:publish-test-2")).start
assert(latch.await(5000, TimeUnit.MILLISECONDS))
@@ -55,6 +56,25 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
assert(response1 === "received msg1")
assert(response2 === "received msg2")
}
+
+ scenario("access blocking, non-responding consumer actor via a Camel direct-endpoint") {
+
+ given("a consumer actor registered after CamelService startup")
+ val latch = service.expectEndpointActivationCount(1)
+ actorOf(new TestBlocker("direct:publish-test-3")).start
+ assert(latch.await(5000, TimeUnit.MILLISECONDS))
+
+ try {
+ when("a request is sent to this actor")
+ CamelContextManager.template.requestBody("direct:publish-test-3", "msg3")
+ fail("expected TimoutException not thrown")
+ } catch {
+ case e => {
+ then("a TimoutException should be thrown")
+ assert(e.getCause.isInstanceOf[TimeoutException])
+ }
+ }
+ }
}
feature("Unpublish registered consumer actor from the global CamelContext") {
@@ -62,24 +82,22 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
scenario("access to unregistered consumer actor via Camel direct-endpoint fails") {
val endpointUri = "direct:unpublish-test-1"
- given("a consumer actor that has been stopped")
+ given("a consumer actor registered after CamelService startup")
assert(CamelContextManager.context.hasEndpoint(endpointUri) eq null)
- var latch = (service.consumerPublisher !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ var latch = service.expectEndpointActivationCount(1)
val consumer = actorOf(new TestConsumer(endpointUri)).start
assert(latch.await(5000, TimeUnit.MILLISECONDS))
assert(CamelContextManager.context.hasEndpoint(endpointUri) ne null)
- latch = (service.consumerPublisher !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ when("the actor is stopped")
+ latch = service.expectEndpointDeactivationCount(1)
consumer.stop
assert(latch.await(5000, TimeUnit.MILLISECONDS))
- // endpoint is still there but the route has been stopped
- assert(CamelContextManager.context.hasEndpoint(endpointUri) ne null)
- when("a request is sent to this actor")
- val response1 = CamelContextManager.template.requestBody(endpointUri, "msg1")
-
- then("the direct-endpoint falls back to its default behaviour and returns the original message")
- assert(response1 === "msg1")
+ then("the associated endpoint isn't accessible any more")
+ intercept[CamelExecutionException] {
+ CamelContextManager.template.requestBody(endpointUri, "msg1")
+ }
}
}
@@ -98,13 +116,13 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
}
}
- feature("Publish active object methods in the global CamelContext") {
+ feature("Publish typed actor methods in the global CamelContext") {
- scenario("access active object methods via Camel direct-endpoints") {
+ scenario("access typed actor methods via Camel direct-endpoints") {
- given("an active object registered after CamelService startup")
- var latch = (service.consumerPublisher !! SetExpectedMessageCount(3)).as[CountDownLatch].get
- val obj = ActiveObject.newInstance(classOf[PojoBase])
+ given("an typed actor registered after CamelService startup")
+ var latch = service.expectEndpointActivationCount(3)
+ val obj = TypedActor.newInstance(classOf[PojoBaseIntf], classOf[PojoBase])
assert(latch.await(5000, TimeUnit.MILLISECONDS))
when("requests are sent to published methods")
@@ -117,35 +135,37 @@ class CamelServiceFeatureTest extends FeatureSpec with BeforeAndAfterAll with Gi
assert(response2 === "m3base: x y")
assert(response3 === "m4base: x y")
- // cleanup to avoid conflicts with next test (i.e. avoid multiple consumers on direct-endpoints)
- latch = (service.consumerPublisher !! SetExpectedMessageCount(3)).as[CountDownLatch].get
- ActiveObject.stop(obj)
+ // cleanup to avoid conflicts with next test (i.e. avoid multiple consumers on direct-endpoints)
+ latch = service.expectEndpointDeactivationCount(3)
+ TypedActor.stop(obj)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
}
}
- feature("Unpublish active object method from the global CamelContext") {
+ feature("Unpublish typed actor method from the global CamelContext") {
- scenario("access to unregistered active object methof via Camel direct-endpoint fails") {
+ scenario("access to unregistered typed actor method via Camel direct-endpoint fails") {
- given("an active object that has been stopped")
- var latch = (service.consumerPublisher !! SetExpectedMessageCount(3)).as[CountDownLatch].get
- val obj = ActiveObject.newInstance(classOf[PojoBase])
+ given("an typed actor registered after CamelService startup")
+ var latch = service.expectEndpointActivationCount(3)
+ val obj = TypedActor.newInstance(classOf[PojoBaseIntf], classOf[PojoBase])
assert(latch.await(5000, TimeUnit.MILLISECONDS))
- latch = (service.consumerPublisher !! SetExpectedMessageCount(3)).as[CountDownLatch].get
- ActiveObject.stop(obj)
+ when("the typed actor is stopped")
+ latch = service.expectEndpointDeactivationCount(3)
+ TypedActor.stop(obj)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
- when("requests are sent to published methods")
- val response1 = CamelContextManager.template.requestBodyAndHeader("direct:m2base", "x", "test", "y")
- val response2 = CamelContextManager.template.requestBodyAndHeader("direct:m3base", "x", "test", "y")
- val response3 = CamelContextManager.template.requestBodyAndHeader("direct:m4base", "x", "test", "y")
-
- then("the direct-endpoints fall back to their default behaviour and return the original message")
- assert(response1 === "x")
- assert(response2 === "x")
- assert(response3 === "x")
+ then("the associated endpoints aren't accessible any more")
+ intercept[CamelExecutionException] {
+ CamelContextManager.template.requestBodyAndHeader("direct:m2base", "x", "test", "y")
+ }
+ intercept[CamelExecutionException] {
+ CamelContextManager.template.requestBodyAndHeader("direct:m3base", "x", "test", "y")
+ }
+ intercept[CamelExecutionException] {
+ CamelContextManager.template.requestBodyAndHeader("direct:m4base", "x", "test", "y")
+ }
}
}
}
@@ -159,6 +179,15 @@ object CamelServiceFeatureTest {
}
}
+ class TestBlocker(uri: String) extends Actor with Consumer {
+ self.timeout = 1000
+ def endpointUri = uri
+ override def blocking = true
+ protected def receive = {
+ case msg: Message => { /* do not reply */ }
+ }
+ }
+
class TestActor extends Actor {
self.id = "custom-actor-id"
protected def receive = {
diff --git a/akka-camel/src/test/scala/ConsumerMethodRegisteredTest.scala b/akka-camel/src/test/scala/ConsumerMethodRegisteredTest.scala
index 7c28c7d8ee..964fe8e7bf 100644
--- a/akka-camel/src/test/scala/ConsumerMethodRegisteredTest.scala
+++ b/akka-camel/src/test/scala/ConsumerMethodRegisteredTest.scala
@@ -4,7 +4,7 @@ import java.net.InetSocketAddress
import org.scalatest.junit.JUnitSuite
-import se.scalablesolutions.akka.actor.{AspectInit, ActiveObject}
+import se.scalablesolutions.akka.actor.{AspectInit, TypedActor}
import se.scalablesolutions.akka.camel.ConsumerMethodRegistered._
import org.junit.{AfterClass, Test}
@@ -12,8 +12,8 @@ class ConsumerMethodRegisteredTest extends JUnitSuite {
import ConsumerMethodRegisteredTest._
val remoteAddress = new InetSocketAddress("localhost", 8888);
- val remoteAspectInit = AspectInit(classOf[String], null, Some(remoteAddress), 1000)
- val localAspectInit = AspectInit(classOf[String], null, None, 1000)
+ val remoteAspectInit = AspectInit(classOf[String], null, null, Some(remoteAddress), 1000)
+ val localAspectInit = AspectInit(classOf[String], null, null, None, 1000)
val ascendingMethodName = (r1: ConsumerMethodRegistered, r2: ConsumerMethodRegistered) =>
r1.method.getName < r2.method.getName
@@ -44,14 +44,14 @@ class ConsumerMethodRegisteredTest extends JUnitSuite {
}
object ConsumerMethodRegisteredTest {
- val activePojoBase = ActiveObject.newInstance(classOf[PojoBase])
- val activePojoSub = ActiveObject.newInstance(classOf[PojoSub])
- val activePojoIntf = ActiveObject.newInstance(classOf[PojoIntf], new PojoImpl)
+ val activePojoBase = TypedActor.newInstance(classOf[PojoBaseIntf], classOf[PojoBase])
+ val activePojoSub = TypedActor.newInstance(classOf[PojoSubIntf], classOf[PojoSub])
+ val activePojoIntf = TypedActor.newInstance(classOf[PojoIntf], classOf[PojoImpl])
@AfterClass
def afterClass = {
- ActiveObject.stop(activePojoBase)
- ActiveObject.stop(activePojoSub)
- ActiveObject.stop(activePojoIntf)
+ TypedActor.stop(activePojoBase)
+ TypedActor.stop(activePojoSub)
+ TypedActor.stop(activePojoIntf)
}
}
diff --git a/akka-camel/src/test/scala/ConsumerRegisteredTest.scala b/akka-camel/src/test/scala/ConsumerRegisteredTest.scala
index caaa03591b..3339caacf2 100644
--- a/akka-camel/src/test/scala/ConsumerRegisteredTest.scala
+++ b/akka-camel/src/test/scala/ConsumerRegisteredTest.scala
@@ -5,17 +5,16 @@ import org.scalatest.junit.JUnitSuite
import se.scalablesolutions.akka.actor.Actor
import se.scalablesolutions.akka.actor.Actor._
-import se.scalablesolutions.akka.actor.annotation.consume
object ConsumerRegisteredTest {
- @consume("mock:test1")
- class ConsumeAnnotatedActor extends Actor {
- self.id = "test"
+ class ConsumerActor1 extends Actor with Consumer {
+ def endpointUri = "mock:test1"
protected def receive = null
}
- class ConsumerActor extends Actor with Consumer {
+ class ConsumerActor2 extends Actor with Consumer {
def endpointUri = "mock:test2"
+ override def blocking = true
protected def receive = null
}
@@ -27,21 +26,14 @@ object ConsumerRegisteredTest {
class ConsumerRegisteredTest extends JUnitSuite {
import ConsumerRegisteredTest._
- @Test def shouldCreatePublishRequestList = {
- val a = actorOf[ConsumeAnnotatedActor]
- val as = List(a)
- val events = for (a <- as; e <- ConsumerRegistered.forConsumer(a)) yield e
- assert(events === List(ConsumerRegistered(a, "mock:test1", "test", false)))
+ @Test def shouldCreateSomeNonBlockingPublishRequest = {
+ val ca = actorOf[ConsumerActor1]
+ val event = ConsumerRegistered.forConsumer(ca)
+ assert(event === Some(ConsumerRegistered(ca, "mock:test1", ca.uuid, false)))
}
- @Test def shouldCreateSomePublishRequestWithActorId = {
- val a = actorOf[ConsumeAnnotatedActor]
- val event = ConsumerRegistered.forConsumer(a)
- assert(event === Some(ConsumerRegistered(a, "mock:test1", "test", false)))
- }
-
- @Test def shouldCreateSomePublishRequestWithActorUuid = {
- val ca = actorOf[ConsumerActor]
+ @Test def shouldCreateSomeBlockingPublishRequest = {
+ val ca = actorOf[ConsumerActor2]
val event = ConsumerRegistered.forConsumer(ca)
assert(event === Some(ConsumerRegistered(ca, "mock:test2", ca.uuid, true)))
}
diff --git a/akka-camel/src/test/scala/ProducerFeatureTest.scala b/akka-camel/src/test/scala/ProducerFeatureTest.scala
index 96d1b9eeef..d238286f9c 100644
--- a/akka-camel/src/test/scala/ProducerFeatureTest.scala
+++ b/akka-camel/src/test/scala/ProducerFeatureTest.scala
@@ -5,14 +5,8 @@ import org.apache.camel.builder.RouteBuilder
import org.apache.camel.component.mock.MockEndpoint
import org.scalatest.{GivenWhenThen, BeforeAndAfterEach, BeforeAndAfterAll, FeatureSpec}
-import se.scalablesolutions.akka.actor.{Actor, ActorRegistry}
import se.scalablesolutions.akka.actor.Actor._
-
-object ProducerFeatureTest {
- class TestProducer(uri: String) extends Actor with Producer {
- def endpointUri = uri
- }
-}
+import se.scalablesolutions.akka.actor.{ActorRef, Actor, ActorRegistry}
class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach with GivenWhenThen {
import ProducerFeatureTest._
@@ -24,109 +18,276 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
CamelContextManager.start
}
- override protected def afterAll = CamelContextManager.stop
+ override protected def afterAll = {
+ CamelContextManager.stop
+ ActorRegistry.shutdownAll
+ }
override protected def afterEach = {
mockEndpoint.reset
- ActorRegistry.shutdownAll
}
feature("Produce a message to a Camel endpoint") {
- scenario("produce message sync and receive response") {
- given("a registered synchronous two-way producer for endpoint direct:producer-test-2")
- val producer = actorOf(new TestProducer("direct:producer-test-2") with Sync)
+ scenario("produce message and receive normal response") {
+ given("a registered two-way producer")
+ val producer = actorOf(new TestProducer("direct:producer-test-2", true))
producer.start
- when("a test message is sent to the producer")
+ when("a test message is sent to the producer with !!")
val message = Message("test", Map(Message.MessageExchangeId -> "123"))
val result = producer !! message
- then("the expected result message should be returned including a correlation identifier")
- val expected = Message("received test", Map(Message.MessageExchangeId -> "123"))
+ then("a normal response should have been returned by the producer")
+ val expected = Message("received TEST", Map(Message.MessageExchangeId -> "123"))
assert(result === Some(expected))
}
- scenario("produce message async and receive response") {
- given("a registered asynchronous two-way producer for endpoint direct:producer-test-2")
+ scenario("produce message and receive failure response") {
+ given("a registered two-way producer")
val producer = actorOf(new TestProducer("direct:producer-test-2"))
producer.start
- when("a test message is sent to the producer")
- val message = Message("test", Map(Message.MessageExchangeId -> "123"))
- val result = producer !! message
-
- then("the expected result message should be returned including a correlation identifier")
- val expected = Message("received test", Map(Message.MessageExchangeId -> "123"))
- assert(result === Some(expected))
- }
-
- scenario("produce message sync and receive failure") {
- given("a registered synchronous two-way producer for endpoint direct:producer-test-2")
- val producer = actorOf(new TestProducer("direct:producer-test-2") with Sync)
- producer.start
-
- when("a fail message is sent to the producer")
+ when("a test message causing an exception is sent to the producer with !!")
val message = Message("fail", Map(Message.MessageExchangeId -> "123"))
val result = (producer !! message).as[Failure]
- then("the expected failure message should be returned including a correlation identifier")
+ then("a failure response should have been returned by the producer")
val expectedFailureText = result.get.cause.getMessage
val expectedHeaders = result.get.headers
assert(expectedFailureText === "failure")
assert(expectedHeaders === Map(Message.MessageExchangeId -> "123"))
}
- scenario("produce message async and receive failure") {
- given("a registered asynchronous two-way producer for endpoint direct:producer-test-2")
- val producer = actorOf(new TestProducer("direct:producer-test-2"))
+ scenario("produce message oneway") {
+ given("a registered one-way producer")
+ val producer = actorOf(new TestProducer("direct:producer-test-1", true) with Oneway)
producer.start
- when("a fail message is sent to the producer")
- val message = Message("fail", Map(Message.MessageExchangeId -> "123"))
- val result = (producer !! message).as[Failure]
-
- then("the expected failure message should be returned including a correlation identifier")
- val expectedFailureText = result.get.cause.getMessage
- val expectedHeaders = result.get.headers
- assert(expectedFailureText === "failure")
- assert(expectedHeaders === Map(Message.MessageExchangeId -> "123"))
- }
-
- scenario("produce message sync oneway") {
- given("a registered synchronous one-way producer for endpoint direct:producer-test-1")
- val producer = actorOf(new TestProducer("direct:producer-test-1") with Sync with Oneway)
- producer.start
-
- when("a test message is sent to the producer")
- mockEndpoint.expectedBodiesReceived("test")
+ when("a test message is sent to the producer with !")
+ mockEndpoint.expectedBodiesReceived("TEST")
producer ! Message("test")
- then("the expected message should have been sent to mock:mock")
+ then("the test message should have been sent to mock:mock")
mockEndpoint.assertIsSatisfied
}
- scenario("produce message async oneway") {
- given("a registered asynchronous one-way producer for endpoint direct:producer-test-1")
- val producer = actorOf(new TestProducer("direct:producer-test-1") with Oneway)
+ scenario("produce message twoway without sender reference") {
+ given("a registered two-way producer")
+ val producer = actorOf(new TestProducer("direct:producer-test-1"))
producer.start
- when("a test message is sent to the producer")
+ when("a test message is sent to the producer with !")
mockEndpoint.expectedBodiesReceived("test")
producer ! Message("test")
- then("the expected message should have been sent to mock:mock")
+ then("there should be only a warning that there's no sender reference")
+ mockEndpoint.assertIsSatisfied
+ }
+ }
+
+ feature("Produce a message to an async Camel endpoint") {
+
+ scenario("produce message and async receive normal response") {
+ given("a registered two-way producer")
+ val producer = actorOf(new TestProducer("direct:producer-test-3"))
+ producer.start
+
+ when("a test message is sent to the producer with !!")
+ val message = Message("test", Map(Message.MessageExchangeId -> "123"))
+ val result = producer !! message
+
+ then("a normal response should have been returned by the producer")
+ val expected = Message("received test", Map(Message.MessageExchangeId -> "123"))
+ assert(result === Some(expected))
+ }
+
+ scenario("produce message and async receive failure response") {
+ given("a registered two-way producer")
+ val producer = actorOf(new TestProducer("direct:producer-test-3"))
+ producer.start
+
+ when("a test message causing an exception is sent to the producer with !!")
+ val message = Message("fail", Map(Message.MessageExchangeId -> "123"))
+ val result = (producer !! message).as[Failure]
+
+ then("a failure response should have been returned by the producer")
+ val expectedFailureText = result.get.cause.getMessage
+ val expectedHeaders = result.get.headers
+ assert(expectedFailureText === "failure")
+ assert(expectedHeaders === Map(Message.MessageExchangeId -> "123"))
+ }
+ }
+
+ feature("Produce a message to a Camel endpoint and then forward the result") {
+
+ scenario("produce message, forward and receive normal response") {
+ given("a registered two-way producer configured with a forward target")
+ val target = actorOf[ReplyingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-2", target)).start
+
+ when("a test message is sent to the producer with !!")
+ val message = Message("test", Map(Message.MessageExchangeId -> "123"))
+ val result = producer !! message
+
+ then("a normal response should have been returned by the forward target")
+ val expected = Message("received test", Map(Message.MessageExchangeId -> "123", "test" -> "result"))
+ assert(result === Some(expected))
+ }
+
+ scenario("produce message, forward and receive failure response") {
+ given("a registered two-way producer configured with a forward target")
+ val target = actorOf[ReplyingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-2", target)).start
+
+ when("a test message causing an exception is sent to the producer with !!")
+ val message = Message("fail", Map(Message.MessageExchangeId -> "123"))
+ val result = (producer !! message).as[Failure]
+
+ then("a failure response should have been returned by the forward target")
+ val expectedFailureText = result.get.cause.getMessage
+ val expectedHeaders = result.get.headers
+ assert(expectedFailureText === "failure")
+ assert(expectedHeaders === Map(Message.MessageExchangeId -> "123", "test" -> "failure"))
+ }
+
+ scenario("produce message, forward and produce normal response") {
+ given("a registered one-way producer configured with a forward target")
+ val target = actorOf[ProducingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-2", target)).start
+
+ when("a test message is sent to the producer with !")
+ mockEndpoint.expectedBodiesReceived("received test")
+ val result = producer.!(Message("test"))(Some(producer))
+
+ then("a normal response should have been produced by the forward target")
+ mockEndpoint.assertIsSatisfied
+ }
+
+ scenario("produce message, forward and produce failure response") {
+ given("a registered one-way producer configured with a forward target")
+ val target = actorOf[ProducingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-2", target)).start
+
+ when("a test message causing an exception is sent to the producer with !")
+ mockEndpoint.expectedMessageCount(1)
+ mockEndpoint.message(0).body().isInstanceOf(classOf[Failure])
+ val result = producer.!(Message("fail"))(Some(producer))
+
+ then("a failure response should have been produced by the forward target")
+ mockEndpoint.assertIsSatisfied
+ }
+ }
+
+ feature("Produce a message to an async Camel endpoint and then forward the result") {
+
+ scenario("produce message, forward and async receive normal response") {
+ given("a registered two-way producer configured with a forward target")
+ val target = actorOf[ReplyingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-3", target)).start
+
+ when("a test message is sent to the producer with !!")
+ val message = Message("test", Map(Message.MessageExchangeId -> "123"))
+ val result = producer !! message
+
+ then("a normal response should have been returned by the forward target")
+ val expected = Message("received test", Map(Message.MessageExchangeId -> "123", "test" -> "result"))
+ assert(result === Some(expected))
+ }
+
+ scenario("produce message, forward and async receive failure response") {
+ given("a registered two-way producer configured with a forward target")
+ val target = actorOf[ReplyingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-3", target)).start
+
+ when("a test message causing an exception is sent to the producer with !!")
+ val message = Message("fail", Map(Message.MessageExchangeId -> "123"))
+ val result = (producer !! message).as[Failure]
+
+ then("a failure response should have been returned by the forward target")
+ val expectedFailureText = result.get.cause.getMessage
+ val expectedHeaders = result.get.headers
+ assert(expectedFailureText === "failure")
+ assert(expectedHeaders === Map(Message.MessageExchangeId -> "123", "test" -> "failure"))
+ }
+
+ scenario("produce message, forward and async produce normal response") {
+ given("a registered one-way producer configured with a forward target")
+ val target = actorOf[ProducingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-3", target)).start
+
+ when("a test message is sent to the producer with !")
+ mockEndpoint.expectedBodiesReceived("received test")
+ val result = producer.!(Message("test"))(Some(producer))
+
+ then("a normal response should have been produced by the forward target")
+ mockEndpoint.assertIsSatisfied
+ }
+
+ scenario("produce message, forward and async produce failure response") {
+ given("a registered one-way producer configured with a forward target")
+ val target = actorOf[ProducingForwardTarget].start
+ val producer = actorOf(new TestForwarder("direct:producer-test-3", target)).start
+
+ when("a test message causing an exception is sent to the producer with !")
+ mockEndpoint.expectedMessageCount(1)
+ mockEndpoint.message(0).body().isInstanceOf(classOf[Failure])
+ val result = producer.!(Message("fail"))(Some(producer))
+
+ then("a failure response should have been produced by the forward target")
mockEndpoint.assertIsSatisfied
}
}
private def mockEndpoint = CamelContextManager.context.getEndpoint("mock:mock", classOf[MockEndpoint])
+}
+
+object ProducerFeatureTest {
+ class TestProducer(uri: String, upper: Boolean = false) extends Actor with Producer {
+ def endpointUri = uri
+ override protected def receiveBeforeProduce = {
+ case msg: Message => if (upper) msg.transformBody[String] { _.toUpperCase } else msg
+ }
+ }
+
+ class TestForwarder(uri: String, target: ActorRef) extends Actor with Producer {
+ def endpointUri = uri
+ override protected def receiveAfterProduce = {
+ case msg => target forward msg
+ }
+ }
+
+ class TestResponder extends Actor {
+ protected def receive = {
+ case msg: Message => msg.body match {
+ case "fail" => self.reply(Failure(new Exception("failure"), msg.headers))
+ case _ => self.reply(msg.transformBody[String] { "received %s" format _ })
+ }
+ }
+ }
+
+ class ReplyingForwardTarget extends Actor {
+ protected def receive = {
+ case msg: Message =>
+ self.reply(msg.addHeader("test" -> "result"))
+ case msg: Failure =>
+ self.reply(Failure(msg.cause, msg.headers + ("test" -> "failure")))
+ }
+ }
+
+ class ProducingForwardTarget extends Actor with Producer with Oneway {
+ def endpointUri = "direct:forward-test-1"
+ }
class TestRoute extends RouteBuilder {
+ val responder = actorOf[TestResponder].start
def configure {
+ from("direct:forward-test-1").to("mock:mock")
// for one-way messaging tests
from("direct:producer-test-1").to("mock:mock")
- // for two-way messaging tests
+ // for two-way messaging tests (async)
+ from("direct:producer-test-3").to("actor:uuid:%s" format responder.uuid)
+ // for two-way messaging tests (sync)
from("direct:producer-test-2").process(new Processor() {
def process(exchange: Exchange) = {
exchange.getIn.getBody match {
diff --git a/akka-camel/src/test/scala/PublishRequestorTest.scala b/akka-camel/src/test/scala/PublishRequestorTest.scala
index 44c6c30684..2913a5981c 100644
--- a/akka-camel/src/test/scala/PublishRequestorTest.scala
+++ b/akka-camel/src/test/scala/PublishRequestorTest.scala
@@ -32,28 +32,28 @@ class PublishRequestorTest extends JUnitSuite {
}
@Test def shouldReceiveConsumerMethodRegisteredEvent = {
- val obj = ActiveObject.newInstance(classOf[PojoSingle])
- val init = AspectInit(classOf[PojoSingle], null, None, 1000)
+ val obj = TypedActor.newInstance(classOf[PojoSingleIntf], classOf[PojoSingle])
+ val init = AspectInit(classOf[PojoSingleIntf], null, null, None, 1000)
val latch = (publisher !! SetExpectedTestMessageCount(1)).as[CountDownLatch].get
requestor ! AspectInitRegistered(obj, init)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
val event = (publisher !! GetRetainedMessage).get.asInstanceOf[ConsumerMethodRegistered]
assert(event.init === init)
assert(event.uri === "direct:foo")
- assert(event.activeObject === obj)
+ assert(event.typedActor === obj)
assert(event.method.getName === "foo")
}
@Test def shouldReceiveConsumerMethodUnregisteredEvent = {
- val obj = ActiveObject.newInstance(classOf[PojoSingle])
- val init = AspectInit(classOf[PojoSingle], null, None, 1000)
+ val obj = TypedActor.newInstance(classOf[PojoSingleIntf], classOf[PojoSingle])
+ val init = AspectInit(classOf[PojoSingleIntf], null, null, None, 1000)
val latch = (publisher !! SetExpectedTestMessageCount(1)).as[CountDownLatch].get
requestor ! AspectInitUnregistered(obj, init)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
val event = (publisher !! GetRetainedMessage).get.asInstanceOf[ConsumerMethodUnregistered]
assert(event.init === init)
assert(event.uri === "direct:foo")
- assert(event.activeObject === obj)
+ assert(event.typedActor === obj)
assert(event.method.getName === "foo")
}
@@ -62,7 +62,7 @@ class PublishRequestorTest extends JUnitSuite {
requestor ! ActorRegistered(consumer)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
assert((publisher !! GetRetainedMessage) ===
- Some(ConsumerRegistered(consumer, "mock:test", consumer.uuid, true)))
+ Some(ConsumerRegistered(consumer, "mock:test", consumer.uuid, false)))
}
@Test def shouldReceiveConsumerUnregisteredEvent = {
@@ -70,7 +70,7 @@ class PublishRequestorTest extends JUnitSuite {
requestor ! ActorUnregistered(consumer)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
assert((publisher !! GetRetainedMessage) ===
- Some(ConsumerUnregistered(consumer, "mock:test", consumer.uuid, true)))
+ Some(ConsumerUnregistered(consumer, "mock:test", consumer.uuid)))
}
}
diff --git a/akka-camel/src/test/scala/RemoteConsumerTest.scala b/akka-camel/src/test/scala/RemoteConsumerTest.scala
index 7e3b666590..fd5dc52a8b 100644
--- a/akka-camel/src/test/scala/RemoteConsumerTest.scala
+++ b/akka-camel/src/test/scala/RemoteConsumerTest.scala
@@ -5,7 +5,7 @@ import java.util.concurrent.{CountDownLatch, TimeUnit}
import org.scalatest.{GivenWhenThen, BeforeAndAfterAll, FeatureSpec}
import se.scalablesolutions.akka.actor.Actor._
-import se.scalablesolutions.akka.actor.{ActiveObject, ActorRegistry, RemoteActor}
+import se.scalablesolutions.akka.actor.{TypedActor, ActorRegistry, RemoteActor}
import se.scalablesolutions.akka.remote.{RemoteClient, RemoteServer}
/**
@@ -20,7 +20,7 @@ class RemoteConsumerTest extends FeatureSpec with BeforeAndAfterAll with GivenWh
override protected def beforeAll = {
ActorRegistry.shutdownAll
- service = CamelService.newInstance
+ service = CamelServiceFactory.createCamelService
service.load
server = new RemoteServer()
@@ -45,7 +45,7 @@ class RemoteConsumerTest extends FeatureSpec with BeforeAndAfterAll with GivenWh
val consumer = actorOf[RemoteConsumer].start
when("remote consumer publication is triggered")
- val latch = (service.consumerPublisher !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ var latch = service.expectEndpointActivationCount(1)
consumer !! "init"
assert(latch.await(5000, TimeUnit.MILLISECONDS))
@@ -55,19 +55,19 @@ class RemoteConsumerTest extends FeatureSpec with BeforeAndAfterAll with GivenWh
}
}
- feature("Client-initiated remote consumer active object") {
+ feature("Client-initiated remote consumer typed actor") {
scenario("access published remote consumer method") {
- given("a client-initiated remote consumer active object")
- val consumer = ActiveObject.newRemoteInstance(classOf[PojoRemote], host, port)
+ given("a client-initiated remote consumer typed actor")
+ val consumer = TypedActor.newRemoteInstance(classOf[PojoRemoteIntf], classOf[PojoRemote], host, port)
when("remote consumer publication is triggered")
- val latch = (service.consumerPublisher !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ var latch = service.expectEndpointActivationCount(1)
consumer.foo("init")
assert(latch.await(5000, TimeUnit.MILLISECONDS))
then("the published method is accessible via its endpoint URI")
- val response = CamelContextManager.template.requestBody("direct:remote-active-object", "test")
- assert(response === "remote active object: test")
+ val response = CamelContextManager.template.requestBody("direct:remote-typed-actor", "test")
+ assert(response === "remote typed actor: test")
}
}
}
diff --git a/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala b/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala
index b7fd607f28..3817bc239e 100644
--- a/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala
+++ b/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala
@@ -3,23 +3,31 @@ package se.scalablesolutions.akka.camel.component
import java.util.concurrent.{TimeUnit, CountDownLatch}
import org.apache.camel.RuntimeCamelException
+import org.apache.camel.builder.RouteBuilder
+import org.apache.camel.component.mock.MockEndpoint
import org.scalatest.{BeforeAndAfterEach, BeforeAndAfterAll, FeatureSpec}
import se.scalablesolutions.akka.actor.Actor._
import se.scalablesolutions.akka.actor.{ActorRegistry, Actor}
-import se.scalablesolutions.akka.camel.{Message, CamelContextManager}
+import se.scalablesolutions.akka.camel.{Failure, Message, CamelContextManager}
import se.scalablesolutions.akka.camel.support._
class ActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach {
+ import ActorComponentFeatureTest._
+
override protected def beforeAll = {
ActorRegistry.shutdownAll
CamelContextManager.init
+ CamelContextManager.context.addRoutes(new TestRoute)
CamelContextManager.start
}
override protected def afterAll = CamelContextManager.stop
- override protected def afterEach = ActorRegistry.shutdownAll
+ override protected def afterEach = {
+ ActorRegistry.shutdownAll
+ mockEndpoint.reset
+ }
feature("Communicate with an actor from a Camel application using actor endpoint URIs") {
import CamelContextManager.template
@@ -55,8 +63,49 @@ class ActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with
scenario("two-way communication with timeout") {
val actor = actorOf[Tester3].start
intercept[RuntimeCamelException] {
- template.requestBody("actor:uuid:%s" format actor.uuid, "Martin")
+ template.requestBody("actor:uuid:%s?blocking=true" format actor.uuid, "Martin")
}
}
+
+ scenario("two-way async communication with failure response") {
+ mockEndpoint.expectedBodiesReceived("whatever")
+ template.requestBody("direct:failure-test-1", "whatever")
+ mockEndpoint.assertIsSatisfied
+ }
+
+ scenario("two-way sync communication with exception") {
+ mockEndpoint.expectedBodiesReceived("whatever")
+ template.requestBody("direct:failure-test-2", "whatever")
+ mockEndpoint.assertIsSatisfied
+ }
+ }
+
+ private def mockEndpoint = CamelContextManager.context.getEndpoint("mock:mock", classOf[MockEndpoint])
+}
+
+object ActorComponentFeatureTest {
+ class FailWithMessage extends Actor {
+ protected def receive = {
+ case msg: Message => self.reply(Failure(new Exception("test")))
+ }
+ }
+
+ class FailWithException extends Actor {
+ protected def receive = {
+ case msg: Message => throw new Exception("test")
+ }
+ }
+
+ class TestRoute extends RouteBuilder {
+ val failWithMessage = actorOf[FailWithMessage].start
+ val failWithException = actorOf[FailWithException].start
+ def configure {
+ from("direct:failure-test-1")
+ .onException(classOf[Exception]).to("mock:mock").handled(true).end
+ .to("actor:uuid:%s" format failWithMessage.uuid)
+ from("direct:failure-test-2")
+ .onException(classOf[Exception]).to("mock:mock").handled(true).end
+ .to("actor:uuid:%s?blocking=true" format failWithException.uuid)
+ }
}
}
diff --git a/akka-camel/src/test/scala/component/ActorComponentTest.scala b/akka-camel/src/test/scala/component/ActorComponentTest.scala
index 6bf472916b..e27e8c5875 100644
--- a/akka-camel/src/test/scala/component/ActorComponentTest.scala
+++ b/akka-camel/src/test/scala/component/ActorComponentTest.scala
@@ -1,11 +1,12 @@
package se.scalablesolutions.akka.camel.component
+import org.apache.camel.{Endpoint, AsyncProcessor}
import org.apache.camel.impl.DefaultCamelContext
import org.junit._
import org.scalatest.junit.JUnitSuite
class ActorComponentTest extends JUnitSuite {
- val component: ActorComponent = ActorComponentTest.mockComponent
+ val component: ActorComponent = ActorComponentTest.actorComponent
@Test def shouldCreateEndpointWithIdDefined = {
val ep1: ActorEndpoint = component.createEndpoint("actor:abc").asInstanceOf[ActorEndpoint]
@@ -14,21 +15,33 @@ class ActorComponentTest extends JUnitSuite {
assert(ep2.id === Some("abc"))
assert(ep1.uuid === None)
assert(ep2.uuid === None)
+ assert(!ep1.blocking)
+ assert(!ep2.blocking)
}
@Test def shouldCreateEndpointWithUuidDefined = {
val ep: ActorEndpoint = component.createEndpoint("actor:uuid:abc").asInstanceOf[ActorEndpoint]
assert(ep.uuid === Some("abc"))
assert(ep.id === None)
+ assert(!ep.blocking)
+ }
+
+ @Test def shouldCreateEndpointWithBlockingSet = {
+ val ep: ActorEndpoint = component.createEndpoint("actor:uuid:abc?blocking=true").asInstanceOf[ActorEndpoint]
+ assert(ep.uuid === Some("abc"))
+ assert(ep.id === None)
+ assert(ep.blocking)
}
}
object ActorComponentTest {
- def mockComponent = {
+ def actorComponent = {
val component = new ActorComponent
component.setCamelContext(new DefaultCamelContext)
component
}
- def mockEndpoint(uri:String) = mockComponent.createEndpoint(uri)
+ def actorEndpoint(uri:String) = actorComponent.createEndpoint(uri)
+ def actorProducer(endpoint: Endpoint) = endpoint.createProducer
+ def actorAsyncProducer(endpoint: Endpoint) = endpoint.createProducer.asInstanceOf[AsyncProcessor]
}
diff --git a/akka-camel/src/test/scala/component/ActorProducerTest.scala b/akka-camel/src/test/scala/component/ActorProducerTest.scala
index f6d5f88d36..5e8a674e55 100644
--- a/akka-camel/src/test/scala/component/ActorProducerTest.scala
+++ b/akka-camel/src/test/scala/component/ActorProducerTest.scala
@@ -4,7 +4,8 @@ import ActorComponentTest._
import java.util.concurrent.{CountDownLatch, TimeoutException, TimeUnit}
-import org.apache.camel.ExchangePattern
+import org.apache.camel.{AsyncCallback, ExchangePattern}
+
import org.junit.{After, Test}
import org.scalatest.junit.JUnitSuite
import org.scalatest.BeforeAndAfterAll
@@ -15,44 +16,77 @@ import se.scalablesolutions.akka.camel.{Failure, Message}
import se.scalablesolutions.akka.camel.support._
class ActorProducerTest extends JUnitSuite with BeforeAndAfterAll {
+ import ActorProducerTest._
+
@After def tearDown = ActorRegistry.shutdownAll
- @Test def shouldSendMessageToActor = {
+ @Test def shouldSendMessageToActorWithProcessor = {
val actor = actorOf[Tester1].start
val latch = (actor !! SetExpectedMessageCount(1)).as[CountDownLatch].get
- val endpoint = mockEndpoint("actor:uuid:%s" format actor.uuid)
+ val endpoint = actorEndpoint("actor:uuid:%s" format actor.uuid)
val exchange = endpoint.createExchange(ExchangePattern.InOnly)
exchange.getIn.setBody("Martin")
exchange.getIn.setHeader("k1", "v1")
- endpoint.createProducer.process(exchange)
+ actorProducer(endpoint).process(exchange)
assert(latch.await(5000, TimeUnit.MILLISECONDS))
val reply = (actor !! GetRetainedMessage).get.asInstanceOf[Message]
assert(reply.body === "Martin")
assert(reply.headers === Map(Message.MessageExchangeId -> exchange.getExchangeId, "k1" -> "v1"))
}
- @Test def shouldSendMessageToActorAndReceiveResponse = {
+ @Test def shouldSendMessageToActorWithAsyncProcessor = {
+ val actor = actorOf[Tester1].start
+ val latch = (actor !! SetExpectedMessageCount(1)).as[CountDownLatch].get
+ val endpoint = actorEndpoint("actor:uuid:%s" format actor.uuid)
+ val exchange = endpoint.createExchange(ExchangePattern.InOnly)
+ exchange.getIn.setBody("Martin")
+ exchange.getIn.setHeader("k1", "v1")
+ actorAsyncProducer(endpoint).process(exchange, expectSyncCompletion)
+ assert(latch.await(5000, TimeUnit.MILLISECONDS))
+ val reply = (actor !! GetRetainedMessage).get.asInstanceOf[Message]
+ assert(reply.body === "Martin")
+ assert(reply.headers === Map(Message.MessageExchangeId -> exchange.getExchangeId, "k1" -> "v1"))
+ }
+
+ @Test def shouldSendMessageToActorAndReceiveResponseWithProcessor = {
val actor = actorOf(new Tester2 {
override def response(msg: Message) = Message(super.response(msg), Map("k2" -> "v2"))
}).start
- val endpoint = mockEndpoint("actor:uuid:%s" format actor.uuid)
+ val endpoint = actorEndpoint("actor:uuid:%s" format actor.uuid)
val exchange = endpoint.createExchange(ExchangePattern.InOut)
exchange.getIn.setBody("Martin")
exchange.getIn.setHeader("k1", "v1")
- endpoint.createProducer.process(exchange)
+ actorProducer(endpoint).process(exchange)
assert(exchange.getOut.getBody === "Hello Martin")
assert(exchange.getOut.getHeader("k2") === "v2")
}
- @Test def shouldSendMessageToActorAndReceiveFailure = {
+ @Test def shouldSendMessageToActorAndReceiveResponseWithAsyncProcessor = {
val actor = actorOf(new Tester2 {
- override def response(msg: Message) = Failure(new Exception("testmsg"), Map("k3" -> "v3"))
+ override def response(msg: Message) = Message(super.response(msg), Map("k2" -> "v2"))
}).start
- val endpoint = mockEndpoint("actor:uuid:%s" format actor.uuid)
+ val completion = expectAsyncCompletion
+ val endpoint = actorEndpoint("actor:uuid:%s" format actor.uuid)
val exchange = endpoint.createExchange(ExchangePattern.InOut)
exchange.getIn.setBody("Martin")
exchange.getIn.setHeader("k1", "v1")
- endpoint.createProducer.process(exchange)
+ actorAsyncProducer(endpoint).process(exchange, completion)
+ assert(completion.latch.await(5000, TimeUnit.MILLISECONDS))
+ assert(exchange.getOut.getBody === "Hello Martin")
+ assert(exchange.getOut.getHeader("k2") === "v2")
+ }
+
+ @Test def shouldSendMessageToActorAndReceiveFailureWithAsyncProcessor = {
+ val actor = actorOf(new Tester2 {
+ override def response(msg: Message) = Failure(new Exception("testmsg"), Map("k3" -> "v3"))
+ }).start
+ val completion = expectAsyncCompletion
+ val endpoint = actorEndpoint("actor:uuid:%s" format actor.uuid)
+ val exchange = endpoint.createExchange(ExchangePattern.InOut)
+ exchange.getIn.setBody("Martin")
+ exchange.getIn.setHeader("k1", "v1")
+ actorAsyncProducer(endpoint).process(exchange, completion)
+ assert(completion.latch.await(5000, TimeUnit.MILLISECONDS))
assert(exchange.getException.getMessage === "testmsg")
assert(exchange.getOut.getBody === null)
assert(exchange.getOut.getHeader("k3") === null) // headers from failure message are currently ignored
@@ -60,7 +94,7 @@ class ActorProducerTest extends JUnitSuite with BeforeAndAfterAll {
@Test def shouldSendMessageToActorAndTimeout(): Unit = {
val actor = actorOf[Tester3].start
- val endpoint = mockEndpoint("actor:uuid:%s" format actor.uuid)
+ val endpoint = actorEndpoint("actor:uuid:%s" format actor.uuid)
val exchange = endpoint.createExchange(ExchangePattern.InOut)
exchange.getIn.setBody("Martin")
intercept[TimeoutException] {
@@ -68,3 +102,18 @@ class ActorProducerTest extends JUnitSuite with BeforeAndAfterAll {
}
}
}
+
+object ActorProducerTest {
+ def expectSyncCompletion = new AsyncCallback {
+ def done(doneSync: Boolean) = assert(doneSync)
+ }
+
+ def expectAsyncCompletion = new AsyncCallback {
+ val latch = new CountDownLatch(1);
+ def done(doneSync: Boolean) = {
+ assert(!doneSync)
+ latch.countDown
+ }
+ }
+
+}
diff --git a/akka-camel/src/test/scala/component/ActiveObjectComponentFeatureTest.scala b/akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala
similarity index 69%
rename from akka-camel/src/test/scala/component/ActiveObjectComponentFeatureTest.scala
rename to akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala
index d80eedfd7a..12ec9f32ab 100644
--- a/akka-camel/src/test/scala/component/ActiveObjectComponentFeatureTest.scala
+++ b/akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala
@@ -4,7 +4,7 @@ import org.scalatest.{BeforeAndAfterEach, BeforeAndAfterAll, FeatureSpec}
import org.apache.camel.builder.RouteBuilder
import se.scalablesolutions.akka.actor.Actor._
-import se.scalablesolutions.akka.actor.{ActorRegistry, ActiveObject}
+import se.scalablesolutions.akka.actor.{ActorRegistry, TypedActor}
import se.scalablesolutions.akka.camel._
import org.apache.camel.impl.{DefaultCamelContext, SimpleRegistry}
import org.apache.camel.{ResolveEndpointFailedException, ExchangePattern, Exchange, Processor}
@@ -12,14 +12,14 @@ import org.apache.camel.{ResolveEndpointFailedException, ExchangePattern, Exchan
/**
* @author Martin Krasser
*/
-class ActiveObjectComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach {
- import ActiveObjectComponentFeatureTest._
+class TypedActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach {
+ import TypedActorComponentFeatureTest._
import CamelContextManager.template
override protected def beforeAll = {
- val activePojo = ActiveObject.newInstance(classOf[Pojo]) // not a consumer
- val activePojoBase = ActiveObject.newInstance(classOf[PojoBase])
- val activePojoIntf = ActiveObject.newInstance(classOf[PojoIntf], new PojoImpl)
+ val activePojo = TypedActor.newInstance(classOf[PojoNonConsumerIntf], classOf[PojoNonConsumer]) // not a consumer
+ val activePojoBase = TypedActor.newInstance(classOf[PojoBaseIntf], classOf[PojoBase])
+ val activePojoIntf = TypedActor.newInstance(classOf[PojoIntf], classOf[PojoImpl])
val registry = new SimpleRegistry
registry.put("pojo", activePojo)
@@ -28,8 +28,8 @@ class ActiveObjectComponentFeatureTest extends FeatureSpec with BeforeAndAfterAl
CamelContextManager.context.addRoutes(new CustomRouteBuilder)
CamelContextManager.start
- CamelContextManager.activeObjectRegistry.put("base", activePojoBase)
- CamelContextManager.activeObjectRegistry.put("intf", activePojoIntf)
+ CamelContextManager.typedActorRegistry.put("base", activePojoBase)
+ CamelContextManager.typedActorRegistry.put("intf", activePojoIntf)
}
override protected def afterAll = {
@@ -37,8 +37,8 @@ class ActiveObjectComponentFeatureTest extends FeatureSpec with BeforeAndAfterAl
ActorRegistry.shutdownAll
}
- feature("Communicate with an active object from a Camel application using active object endpoint URIs") {
- import ActiveObjectComponent.InternalSchema
+ feature("Communicate with an typed actor from a Camel application using typed actor endpoint URIs") {
+ import TypedActorComponent.InternalSchema
import ExchangePattern._
scenario("in-out exchange with proxy created from interface and method returning String") {
@@ -81,25 +81,25 @@ class ActiveObjectComponentFeatureTest extends FeatureSpec with BeforeAndAfterAl
}
}
- feature("Communicate with an active object from a Camel application from a custom Camel route") {
+ feature("Communicate with an typed actor from a Camel application from a custom Camel route") {
- scenario("in-out exchange with externally registered active object") {
+ scenario("in-out exchange with externally registered typed actor") {
val result = template.requestBody("direct:test", "test")
assert(result === "foo: test")
}
- scenario("in-out exchange with internally registered active object not possible") {
+ scenario("in-out exchange with internally registered typed actor not possible") {
intercept[ResolveEndpointFailedException] {
- template.requestBodyAndHeader("active-object:intf?method=m2", "x", "test", "y")
+ template.requestBodyAndHeader("typed-actor:intf?method=m2", "x", "test", "y")
}
}
}
}
-object ActiveObjectComponentFeatureTest {
+object TypedActorComponentFeatureTest {
class CustomRouteBuilder extends RouteBuilder {
def configure = {
- from("direct:test").to("active-object:pojo?method=foo")
+ from("direct:test").to("typed-actor:pojo?method=foo")
}
}
}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/configuration.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/configuration.java
deleted file mode 100644
index 9c5375398b..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/configuration.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface configuration {}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java
deleted file mode 100644
index 35c5f05afe..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface inittransactionalstate {}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java
deleted file mode 100644
index 5eed474832..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface postrestart {}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java
deleted file mode 100644
index 94f9a01405..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface prerestart {}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/shutdown.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/shutdown.java
deleted file mode 100644
index f806e7bca6..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/shutdown.java
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface shutdown {}
\ No newline at end of file
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/state.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/state.java
deleted file mode 100644
index 509d129c1b..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/state.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface state {}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java b/akka-core/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java
deleted file mode 100644
index c41a09ee46..0000000000
--- a/akka-core/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor.annotation;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface transactionrequired {}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/config/ActiveObjectGuiceModule.java b/akka-core/src/main/java/se/scalablesolutions/akka/config/TypedActorGuiceModule.java
similarity index 85%
rename from akka-core/src/main/java/se/scalablesolutions/akka/config/ActiveObjectGuiceModule.java
rename to akka-core/src/main/java/se/scalablesolutions/akka/config/TypedActorGuiceModule.java
index 60dfd4cadd..0c2ed11402 100644
--- a/akka-core/src/main/java/se/scalablesolutions/akka/config/ActiveObjectGuiceModule.java
+++ b/akka-core/src/main/java/se/scalablesolutions/akka/config/TypedActorGuiceModule.java
@@ -13,10 +13,10 @@ import com.google.inject.Singleton;
/**
* @author Jonas Bonér
*/
-public class ActiveObjectGuiceModule extends AbstractModule {
+public class TypedActorGuiceModule extends AbstractModule {
private final List bindings;
- public ActiveObjectGuiceModule(final List bindings) {
+ public TypedActorGuiceModule(final List bindings) {
this.bindings = bindings;
}
diff --git a/akka-core/src/main/java/se/scalablesolutions/akka/remote/protocol/RemoteProtocol.java b/akka-core/src/main/java/se/scalablesolutions/akka/remote/protocol/RemoteProtocol.java
index 648f53842b..8babc16770 100644
--- a/akka-core/src/main/java/se/scalablesolutions/akka/remote/protocol/RemoteProtocol.java
+++ b/akka-core/src/main/java/se/scalablesolutions/akka/remote/protocol/RemoteProtocol.java
@@ -8,6 +8,75 @@ public final class RemoteProtocol {
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
}
+ public enum ActorType
+ implements com.google.protobuf.ProtocolMessageEnum {
+ SCALA_ACTOR(0, 1),
+ JAVA_ACTOR(1, 2),
+ TYPED_ACTOR(2, 3),
+ ;
+
+
+ public final int getNumber() { return value; }
+
+ public static ActorType valueOf(int value) {
+ switch (value) {
+ case 1: return SCALA_ACTOR;
+ case 2: return JAVA_ACTOR;
+ case 3: return TYPED_ACTOR;
+ default: return null;
+ }
+ }
+
+ public static com.google.protobuf.Internal.EnumLiteMap
+ internalGetValueMap() {
+ return internalValueMap;
+ }
+ private static com.google.protobuf.Internal.EnumLiteMap
+ internalValueMap =
+ new com.google.protobuf.Internal.EnumLiteMap() {
+ public ActorType findValueByNumber(int number) {
+ return ActorType.valueOf(number)
+ ; }
+ };
+
+ public final com.google.protobuf.Descriptors.EnumValueDescriptor
+ getValueDescriptor() {
+ return getDescriptor().getValues().get(index);
+ }
+ public final com.google.protobuf.Descriptors.EnumDescriptor
+ getDescriptorForType() {
+ return getDescriptor();
+ }
+ public static final com.google.protobuf.Descriptors.EnumDescriptor
+ getDescriptor() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.getDescriptor().getEnumTypes().get(0);
+ }
+
+ private static final ActorType[] VALUES = {
+ SCALA_ACTOR, JAVA_ACTOR, TYPED_ACTOR,
+ };
+ public static ActorType valueOf(
+ com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+ if (desc.getType() != getDescriptor()) {
+ throw new java.lang.IllegalArgumentException(
+ "EnumValueDescriptor is not for this type.");
+ }
+ return VALUES[desc.getIndex()];
+ }
+ private final int index;
+ private final int value;
+ private ActorType(int index, int value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ static {
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.getDescriptor();
+ }
+
+ // @@protoc_insertion_point(enum_scope:ActorType)
+ }
+
public enum SerializationSchemeType
implements com.google.protobuf.ProtocolMessageEnum {
JAVA(0, 1),
@@ -53,7 +122,7 @@ public final class RemoteProtocol {
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
- return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.getDescriptor().getEnumTypes().get(0);
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.getDescriptor().getEnumTypes().get(1);
}
private static final SerializationSchemeType[] VALUES = {
@@ -120,7 +189,7 @@ public final class RemoteProtocol {
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
- return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.getDescriptor().getEnumTypes().get(1);
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.getDescriptor().getEnumTypes().get(2);
}
private static final LifeCycleType[] VALUES = {
@@ -667,29 +736,36 @@ public final class RemoteProtocol {
public boolean hasTimeout() { return hasTimeout; }
public long getTimeout() { return timeout_; }
- // optional .LifeCycleProtocol lifeCycle = 9;
- public static final int LIFECYCLE_FIELD_NUMBER = 9;
+ // optional uint64 receiveTimeout = 9;
+ public static final int RECEIVETIMEOUT_FIELD_NUMBER = 9;
+ private boolean hasReceiveTimeout;
+ private long receiveTimeout_ = 0L;
+ public boolean hasReceiveTimeout() { return hasReceiveTimeout; }
+ public long getReceiveTimeout() { return receiveTimeout_; }
+
+ // optional .LifeCycleProtocol lifeCycle = 10;
+ public static final int LIFECYCLE_FIELD_NUMBER = 10;
private boolean hasLifeCycle;
private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleProtocol lifeCycle_;
public boolean hasLifeCycle() { return hasLifeCycle; }
public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleProtocol getLifeCycle() { return lifeCycle_; }
- // optional .RemoteActorRefProtocol supervisor = 10;
- public static final int SUPERVISOR_FIELD_NUMBER = 10;
+ // optional .RemoteActorRefProtocol supervisor = 11;
+ public static final int SUPERVISOR_FIELD_NUMBER = 11;
private boolean hasSupervisor;
private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol supervisor_;
public boolean hasSupervisor() { return hasSupervisor; }
public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol getSupervisor() { return supervisor_; }
- // optional bytes hotswapStack = 11;
- public static final int HOTSWAPSTACK_FIELD_NUMBER = 11;
+ // optional bytes hotswapStack = 12;
+ public static final int HOTSWAPSTACK_FIELD_NUMBER = 12;
private boolean hasHotswapStack;
private com.google.protobuf.ByteString hotswapStack_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasHotswapStack() { return hasHotswapStack; }
public com.google.protobuf.ByteString getHotswapStack() { return hotswapStack_; }
- // repeated .RemoteRequestProtocol messages = 12;
- public static final int MESSAGES_FIELD_NUMBER = 12;
+ // repeated .RemoteRequestProtocol messages = 13;
+ public static final int MESSAGES_FIELD_NUMBER = 13;
private java.util.List messages_ =
java.util.Collections.emptyList();
public java.util.List getMessagesList() {
@@ -750,17 +826,20 @@ public final class RemoteProtocol {
if (hasTimeout()) {
output.writeUInt64(8, getTimeout());
}
+ if (hasReceiveTimeout()) {
+ output.writeUInt64(9, getReceiveTimeout());
+ }
if (hasLifeCycle()) {
- output.writeMessage(9, getLifeCycle());
+ output.writeMessage(10, getLifeCycle());
}
if (hasSupervisor()) {
- output.writeMessage(10, getSupervisor());
+ output.writeMessage(11, getSupervisor());
}
if (hasHotswapStack()) {
- output.writeBytes(11, getHotswapStack());
+ output.writeBytes(12, getHotswapStack());
}
for (se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol element : getMessagesList()) {
- output.writeMessage(12, element);
+ output.writeMessage(13, element);
}
getUnknownFields().writeTo(output);
}
@@ -803,21 +882,25 @@ public final class RemoteProtocol {
size += com.google.protobuf.CodedOutputStream
.computeUInt64Size(8, getTimeout());
}
+ if (hasReceiveTimeout()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt64Size(9, getReceiveTimeout());
+ }
if (hasLifeCycle()) {
size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(9, getLifeCycle());
+ .computeMessageSize(10, getLifeCycle());
}
if (hasSupervisor()) {
size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(10, getSupervisor());
+ .computeMessageSize(11, getSupervisor());
}
if (hasHotswapStack()) {
size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(11, getHotswapStack());
+ .computeBytesSize(12, getHotswapStack());
}
for (se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol element : getMessagesList()) {
size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(12, element);
+ .computeMessageSize(13, element);
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
@@ -1005,6 +1088,9 @@ public final class RemoteProtocol {
if (other.hasTimeout()) {
setTimeout(other.getTimeout());
}
+ if (other.hasReceiveTimeout()) {
+ setReceiveTimeout(other.getReceiveTimeout());
+ }
if (other.hasLifeCycle()) {
mergeLifeCycle(other.getLifeCycle());
}
@@ -1082,7 +1168,11 @@ public final class RemoteProtocol {
setTimeout(input.readUInt64());
break;
}
- case 74: {
+ case 72: {
+ setReceiveTimeout(input.readUInt64());
+ break;
+ }
+ case 82: {
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleProtocol.Builder subBuilder = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleProtocol.newBuilder();
if (hasLifeCycle()) {
subBuilder.mergeFrom(getLifeCycle());
@@ -1091,7 +1181,7 @@ public final class RemoteProtocol {
setLifeCycle(subBuilder.buildPartial());
break;
}
- case 82: {
+ case 90: {
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol.Builder subBuilder = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol.newBuilder();
if (hasSupervisor()) {
subBuilder.mergeFrom(getSupervisor());
@@ -1100,11 +1190,11 @@ public final class RemoteProtocol {
setSupervisor(subBuilder.buildPartial());
break;
}
- case 90: {
+ case 98: {
setHotswapStack(input.readBytes());
break;
}
- case 98: {
+ case 106: {
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol.Builder subBuilder = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol.newBuilder();
input.readMessage(subBuilder, extensionRegistry);
addMessages(subBuilder.buildPartial());
@@ -1293,7 +1383,25 @@ public final class RemoteProtocol {
return this;
}
- // optional .LifeCycleProtocol lifeCycle = 9;
+ // optional uint64 receiveTimeout = 9;
+ public boolean hasReceiveTimeout() {
+ return result.hasReceiveTimeout();
+ }
+ public long getReceiveTimeout() {
+ return result.getReceiveTimeout();
+ }
+ public Builder setReceiveTimeout(long value) {
+ result.hasReceiveTimeout = true;
+ result.receiveTimeout_ = value;
+ return this;
+ }
+ public Builder clearReceiveTimeout() {
+ result.hasReceiveTimeout = false;
+ result.receiveTimeout_ = 0L;
+ return this;
+ }
+
+ // optional .LifeCycleProtocol lifeCycle = 10;
public boolean hasLifeCycle() {
return result.hasLifeCycle();
}
@@ -1330,7 +1438,7 @@ public final class RemoteProtocol {
return this;
}
- // optional .RemoteActorRefProtocol supervisor = 10;
+ // optional .RemoteActorRefProtocol supervisor = 11;
public boolean hasSupervisor() {
return result.hasSupervisor();
}
@@ -1367,7 +1475,7 @@ public final class RemoteProtocol {
return this;
}
- // optional bytes hotswapStack = 11;
+ // optional bytes hotswapStack = 12;
public boolean hasHotswapStack() {
return result.hasHotswapStack();
}
@@ -1388,7 +1496,7 @@ public final class RemoteProtocol {
return this;
}
- // repeated .RemoteRequestProtocol messages = 12;
+ // repeated .RemoteRequestProtocol messages = 13;
public java.util.List getMessagesList() {
return java.util.Collections.unmodifiableList(result.messages_);
}
@@ -1831,6 +1939,825 @@ public final class RemoteProtocol {
// @@protoc_insertion_point(class_scope:MessageProtocol)
}
+ public static final class ActorInfoProtocol extends
+ com.google.protobuf.GeneratedMessage {
+ // Use ActorInfoProtocol.newBuilder() to construct.
+ private ActorInfoProtocol() {
+ initFields();
+ }
+ private ActorInfoProtocol(boolean noInit) {}
+
+ private static final ActorInfoProtocol defaultInstance;
+ public static ActorInfoProtocol getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public ActorInfoProtocol getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.internal_static_ActorInfoProtocol_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.internal_static_ActorInfoProtocol_fieldAccessorTable;
+ }
+
+ // required string uuid = 1;
+ public static final int UUID_FIELD_NUMBER = 1;
+ private boolean hasUuid;
+ private java.lang.String uuid_ = "";
+ public boolean hasUuid() { return hasUuid; }
+ public java.lang.String getUuid() { return uuid_; }
+
+ // required string target = 2;
+ public static final int TARGET_FIELD_NUMBER = 2;
+ private boolean hasTarget;
+ private java.lang.String target_ = "";
+ public boolean hasTarget() { return hasTarget; }
+ public java.lang.String getTarget() { return target_; }
+
+ // required uint64 timeout = 3;
+ public static final int TIMEOUT_FIELD_NUMBER = 3;
+ private boolean hasTimeout;
+ private long timeout_ = 0L;
+ public boolean hasTimeout() { return hasTimeout; }
+ public long getTimeout() { return timeout_; }
+
+ // required .ActorType actorType = 4;
+ public static final int ACTORTYPE_FIELD_NUMBER = 4;
+ private boolean hasActorType;
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType actorType_;
+ public boolean hasActorType() { return hasActorType; }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType getActorType() { return actorType_; }
+
+ // optional .TypedActorInfoProtocol typedActorInfo = 5;
+ public static final int TYPEDACTORINFO_FIELD_NUMBER = 5;
+ private boolean hasTypedActorInfo;
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol typedActorInfo_;
+ public boolean hasTypedActorInfo() { return hasTypedActorInfo; }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol getTypedActorInfo() { return typedActorInfo_; }
+
+ private void initFields() {
+ actorType_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType.SCALA_ACTOR;
+ typedActorInfo_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.getDefaultInstance();
+ }
+ public final boolean isInitialized() {
+ if (!hasUuid) return false;
+ if (!hasTarget) return false;
+ if (!hasTimeout) return false;
+ if (!hasActorType) return false;
+ if (hasTypedActorInfo()) {
+ if (!getTypedActorInfo().isInitialized()) return false;
+ }
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (hasUuid()) {
+ output.writeString(1, getUuid());
+ }
+ if (hasTarget()) {
+ output.writeString(2, getTarget());
+ }
+ if (hasTimeout()) {
+ output.writeUInt64(3, getTimeout());
+ }
+ if (hasActorType()) {
+ output.writeEnum(4, getActorType().getNumber());
+ }
+ if (hasTypedActorInfo()) {
+ output.writeMessage(5, getTypedActorInfo());
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasUuid()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(1, getUuid());
+ }
+ if (hasTarget()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(2, getTarget());
+ }
+ if (hasTimeout()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt64Size(3, getTimeout());
+ }
+ if (hasActorType()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeEnumSize(4, getActorType().getNumber());
+ }
+ if (hasTypedActorInfo()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(5, getTypedActorInfo());
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder {
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol result;
+
+ // Construct using se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.newBuilder()
+ private Builder() {}
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.result = new se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol();
+ return builder;
+ }
+
+ protected se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol internalGetResult() {
+ return result;
+ }
+
+ public Builder clear() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "Cannot call clear() after build().");
+ }
+ result = new se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol();
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(result);
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.getDescriptor();
+ }
+
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol getDefaultInstanceForType() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.getDefaultInstance();
+ }
+
+ public boolean isInitialized() {
+ return result.isInitialized();
+ }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol build() {
+ if (result != null && !isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return buildPartial();
+ }
+
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol buildPartial() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "build() has already been called on this Builder.");
+ }
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol) {
+ return mergeFrom((se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol other) {
+ if (other == se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.getDefaultInstance()) return this;
+ if (other.hasUuid()) {
+ setUuid(other.getUuid());
+ }
+ if (other.hasTarget()) {
+ setTarget(other.getTarget());
+ }
+ if (other.hasTimeout()) {
+ setTimeout(other.getTimeout());
+ }
+ if (other.hasActorType()) {
+ setActorType(other.getActorType());
+ }
+ if (other.hasTypedActorInfo()) {
+ mergeTypedActorInfo(other.getTypedActorInfo());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ return this;
+ }
+ break;
+ }
+ case 10: {
+ setUuid(input.readString());
+ break;
+ }
+ case 18: {
+ setTarget(input.readString());
+ break;
+ }
+ case 24: {
+ setTimeout(input.readUInt64());
+ break;
+ }
+ case 32: {
+ int rawValue = input.readEnum();
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType value = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType.valueOf(rawValue);
+ if (value == null) {
+ unknownFields.mergeVarintField(4, rawValue);
+ } else {
+ setActorType(value);
+ }
+ break;
+ }
+ case 42: {
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.Builder subBuilder = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.newBuilder();
+ if (hasTypedActorInfo()) {
+ subBuilder.mergeFrom(getTypedActorInfo());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setTypedActorInfo(subBuilder.buildPartial());
+ break;
+ }
+ }
+ }
+ }
+
+
+ // required string uuid = 1;
+ public boolean hasUuid() {
+ return result.hasUuid();
+ }
+ public java.lang.String getUuid() {
+ return result.getUuid();
+ }
+ public Builder setUuid(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasUuid = true;
+ result.uuid_ = value;
+ return this;
+ }
+ public Builder clearUuid() {
+ result.hasUuid = false;
+ result.uuid_ = getDefaultInstance().getUuid();
+ return this;
+ }
+
+ // required string target = 2;
+ public boolean hasTarget() {
+ return result.hasTarget();
+ }
+ public java.lang.String getTarget() {
+ return result.getTarget();
+ }
+ public Builder setTarget(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasTarget = true;
+ result.target_ = value;
+ return this;
+ }
+ public Builder clearTarget() {
+ result.hasTarget = false;
+ result.target_ = getDefaultInstance().getTarget();
+ return this;
+ }
+
+ // required uint64 timeout = 3;
+ public boolean hasTimeout() {
+ return result.hasTimeout();
+ }
+ public long getTimeout() {
+ return result.getTimeout();
+ }
+ public Builder setTimeout(long value) {
+ result.hasTimeout = true;
+ result.timeout_ = value;
+ return this;
+ }
+ public Builder clearTimeout() {
+ result.hasTimeout = false;
+ result.timeout_ = 0L;
+ return this;
+ }
+
+ // required .ActorType actorType = 4;
+ public boolean hasActorType() {
+ return result.hasActorType();
+ }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType getActorType() {
+ return result.getActorType();
+ }
+ public Builder setActorType(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasActorType = true;
+ result.actorType_ = value;
+ return this;
+ }
+ public Builder clearActorType() {
+ result.hasActorType = false;
+ result.actorType_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorType.SCALA_ACTOR;
+ return this;
+ }
+
+ // optional .TypedActorInfoProtocol typedActorInfo = 5;
+ public boolean hasTypedActorInfo() {
+ return result.hasTypedActorInfo();
+ }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol getTypedActorInfo() {
+ return result.getTypedActorInfo();
+ }
+ public Builder setTypedActorInfo(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasTypedActorInfo = true;
+ result.typedActorInfo_ = value;
+ return this;
+ }
+ public Builder setTypedActorInfo(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.Builder builderForValue) {
+ result.hasTypedActorInfo = true;
+ result.typedActorInfo_ = builderForValue.build();
+ return this;
+ }
+ public Builder mergeTypedActorInfo(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol value) {
+ if (result.hasTypedActorInfo() &&
+ result.typedActorInfo_ != se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.getDefaultInstance()) {
+ result.typedActorInfo_ =
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.newBuilder(result.typedActorInfo_).mergeFrom(value).buildPartial();
+ } else {
+ result.typedActorInfo_ = value;
+ }
+ result.hasTypedActorInfo = true;
+ return this;
+ }
+ public Builder clearTypedActorInfo() {
+ result.hasTypedActorInfo = false;
+ result.typedActorInfo_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.getDefaultInstance();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:ActorInfoProtocol)
+ }
+
+ static {
+ defaultInstance = new ActorInfoProtocol(true);
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.internalForceInit();
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:ActorInfoProtocol)
+ }
+
+ public static final class TypedActorInfoProtocol extends
+ com.google.protobuf.GeneratedMessage {
+ // Use TypedActorInfoProtocol.newBuilder() to construct.
+ private TypedActorInfoProtocol() {
+ initFields();
+ }
+ private TypedActorInfoProtocol(boolean noInit) {}
+
+ private static final TypedActorInfoProtocol defaultInstance;
+ public static TypedActorInfoProtocol getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public TypedActorInfoProtocol getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.internal_static_TypedActorInfoProtocol_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.internal_static_TypedActorInfoProtocol_fieldAccessorTable;
+ }
+
+ // required string interface = 1;
+ public static final int INTERFACE_FIELD_NUMBER = 1;
+ private boolean hasInterface;
+ private java.lang.String interface_ = "";
+ public boolean hasInterface() { return hasInterface; }
+ public java.lang.String getInterface() { return interface_; }
+
+ // required string method = 2;
+ public static final int METHOD_FIELD_NUMBER = 2;
+ private boolean hasMethod;
+ private java.lang.String method_ = "";
+ public boolean hasMethod() { return hasMethod; }
+ public java.lang.String getMethod() { return method_; }
+
+ private void initFields() {
+ }
+ public final boolean isInitialized() {
+ if (!hasInterface) return false;
+ if (!hasMethod) return false;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (hasInterface()) {
+ output.writeString(1, getInterface());
+ }
+ if (hasMethod()) {
+ output.writeString(2, getMethod());
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasInterface()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(1, getInterface());
+ }
+ if (hasMethod()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(2, getMethod());
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder {
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol result;
+
+ // Construct using se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.newBuilder()
+ private Builder() {}
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.result = new se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol();
+ return builder;
+ }
+
+ protected se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol internalGetResult() {
+ return result;
+ }
+
+ public Builder clear() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "Cannot call clear() after build().");
+ }
+ result = new se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol();
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(result);
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.getDescriptor();
+ }
+
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol getDefaultInstanceForType() {
+ return se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.getDefaultInstance();
+ }
+
+ public boolean isInitialized() {
+ return result.isInitialized();
+ }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol build() {
+ if (result != null && !isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return buildPartial();
+ }
+
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol buildPartial() {
+ if (result == null) {
+ throw new IllegalStateException(
+ "build() has already been called on this Builder.");
+ }
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol) {
+ return mergeFrom((se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol other) {
+ if (other == se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.getDefaultInstance()) return this;
+ if (other.hasInterface()) {
+ setInterface(other.getInterface());
+ }
+ if (other.hasMethod()) {
+ setMethod(other.getMethod());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ return this;
+ }
+ break;
+ }
+ case 10: {
+ setInterface(input.readString());
+ break;
+ }
+ case 18: {
+ setMethod(input.readString());
+ break;
+ }
+ }
+ }
+ }
+
+
+ // required string interface = 1;
+ public boolean hasInterface() {
+ return result.hasInterface();
+ }
+ public java.lang.String getInterface() {
+ return result.getInterface();
+ }
+ public Builder setInterface(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasInterface = true;
+ result.interface_ = value;
+ return this;
+ }
+ public Builder clearInterface() {
+ result.hasInterface = false;
+ result.interface_ = getDefaultInstance().getInterface();
+ return this;
+ }
+
+ // required string method = 2;
+ public boolean hasMethod() {
+ return result.hasMethod();
+ }
+ public java.lang.String getMethod() {
+ return result.getMethod();
+ }
+ public Builder setMethod(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasMethod = true;
+ result.method_ = value;
+ return this;
+ }
+ public Builder clearMethod() {
+ result.hasMethod = false;
+ result.method_ = getDefaultInstance().getMethod();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:TypedActorInfoProtocol)
+ }
+
+ static {
+ defaultInstance = new TypedActorInfoProtocol(true);
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.internalForceInit();
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:TypedActorInfoProtocol)
+ }
+
public static final class RemoteRequestProtocol extends
com.google.protobuf.GeneratedMessage {
// Use RemoteRequestProtocol.newBuilder() to construct.
@@ -1872,64 +2799,29 @@ public final class RemoteProtocol {
public boolean hasMessage() { return hasMessage; }
public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.MessageProtocol getMessage() { return message_; }
- // optional string method = 3;
- public static final int METHOD_FIELD_NUMBER = 3;
- private boolean hasMethod;
- private java.lang.String method_ = "";
- public boolean hasMethod() { return hasMethod; }
- public java.lang.String getMethod() { return method_; }
+ // required .ActorInfoProtocol actorInfo = 3;
+ public static final int ACTORINFO_FIELD_NUMBER = 3;
+ private boolean hasActorInfo;
+ private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol actorInfo_;
+ public boolean hasActorInfo() { return hasActorInfo; }
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol getActorInfo() { return actorInfo_; }
- // required string target = 4;
- public static final int TARGET_FIELD_NUMBER = 4;
- private boolean hasTarget;
- private java.lang.String target_ = "";
- public boolean hasTarget() { return hasTarget; }
- public java.lang.String getTarget() { return target_; }
-
- // required string uuid = 5;
- public static final int UUID_FIELD_NUMBER = 5;
- private boolean hasUuid;
- private java.lang.String uuid_ = "";
- public boolean hasUuid() { return hasUuid; }
- public java.lang.String getUuid() { return uuid_; }
-
- // required uint64 timeout = 6;
- public static final int TIMEOUT_FIELD_NUMBER = 6;
- private boolean hasTimeout;
- private long timeout_ = 0L;
- public boolean hasTimeout() { return hasTimeout; }
- public long getTimeout() { return timeout_; }
-
- // optional string supervisorUuid = 7;
- public static final int SUPERVISORUUID_FIELD_NUMBER = 7;
- private boolean hasSupervisorUuid;
- private java.lang.String supervisorUuid_ = "";
- public boolean hasSupervisorUuid() { return hasSupervisorUuid; }
- public java.lang.String getSupervisorUuid() { return supervisorUuid_; }
-
- // required bool isActor = 8;
- public static final int ISACTOR_FIELD_NUMBER = 8;
- private boolean hasIsActor;
- private boolean isActor_ = false;
- public boolean hasIsActor() { return hasIsActor; }
- public boolean getIsActor() { return isActor_; }
-
- // required bool isOneWay = 9;
- public static final int ISONEWAY_FIELD_NUMBER = 9;
+ // required bool isOneWay = 4;
+ public static final int ISONEWAY_FIELD_NUMBER = 4;
private boolean hasIsOneWay;
private boolean isOneWay_ = false;
public boolean hasIsOneWay() { return hasIsOneWay; }
public boolean getIsOneWay() { return isOneWay_; }
- // required bool isEscaped = 10;
- public static final int ISESCAPED_FIELD_NUMBER = 10;
- private boolean hasIsEscaped;
- private boolean isEscaped_ = false;
- public boolean hasIsEscaped() { return hasIsEscaped; }
- public boolean getIsEscaped() { return isEscaped_; }
+ // optional string supervisorUuid = 5;
+ public static final int SUPERVISORUUID_FIELD_NUMBER = 5;
+ private boolean hasSupervisorUuid;
+ private java.lang.String supervisorUuid_ = "";
+ public boolean hasSupervisorUuid() { return hasSupervisorUuid; }
+ public java.lang.String getSupervisorUuid() { return supervisorUuid_; }
- // optional .RemoteActorRefProtocol sender = 11;
- public static final int SENDER_FIELD_NUMBER = 11;
+ // optional .RemoteActorRefProtocol sender = 6;
+ public static final int SENDER_FIELD_NUMBER = 6;
private boolean hasSender;
private se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol sender_;
public boolean hasSender() { return hasSender; }
@@ -1937,18 +2829,16 @@ public final class RemoteProtocol {
private void initFields() {
message_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.MessageProtocol.getDefaultInstance();
+ actorInfo_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.getDefaultInstance();
sender_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol.getDefaultInstance();
}
public final boolean isInitialized() {
if (!hasId) return false;
if (!hasMessage) return false;
- if (!hasTarget) return false;
- if (!hasUuid) return false;
- if (!hasTimeout) return false;
- if (!hasIsActor) return false;
+ if (!hasActorInfo) return false;
if (!hasIsOneWay) return false;
- if (!hasIsEscaped) return false;
if (!getMessage().isInitialized()) return false;
+ if (!getActorInfo().isInitialized()) return false;
if (hasSender()) {
if (!getSender().isInitialized()) return false;
}
@@ -1964,32 +2854,17 @@ public final class RemoteProtocol {
if (hasMessage()) {
output.writeMessage(2, getMessage());
}
- if (hasMethod()) {
- output.writeString(3, getMethod());
- }
- if (hasTarget()) {
- output.writeString(4, getTarget());
- }
- if (hasUuid()) {
- output.writeString(5, getUuid());
- }
- if (hasTimeout()) {
- output.writeUInt64(6, getTimeout());
- }
- if (hasSupervisorUuid()) {
- output.writeString(7, getSupervisorUuid());
- }
- if (hasIsActor()) {
- output.writeBool(8, getIsActor());
+ if (hasActorInfo()) {
+ output.writeMessage(3, getActorInfo());
}
if (hasIsOneWay()) {
- output.writeBool(9, getIsOneWay());
+ output.writeBool(4, getIsOneWay());
}
- if (hasIsEscaped()) {
- output.writeBool(10, getIsEscaped());
+ if (hasSupervisorUuid()) {
+ output.writeString(5, getSupervisorUuid());
}
if (hasSender()) {
- output.writeMessage(11, getSender());
+ output.writeMessage(6, getSender());
}
getUnknownFields().writeTo(output);
}
@@ -2008,41 +2883,21 @@ public final class RemoteProtocol {
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(2, getMessage());
}
- if (hasMethod()) {
+ if (hasActorInfo()) {
size += com.google.protobuf.CodedOutputStream
- .computeStringSize(3, getMethod());
- }
- if (hasTarget()) {
- size += com.google.protobuf.CodedOutputStream
- .computeStringSize(4, getTarget());
- }
- if (hasUuid()) {
- size += com.google.protobuf.CodedOutputStream
- .computeStringSize(5, getUuid());
- }
- if (hasTimeout()) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt64Size(6, getTimeout());
- }
- if (hasSupervisorUuid()) {
- size += com.google.protobuf.CodedOutputStream
- .computeStringSize(7, getSupervisorUuid());
- }
- if (hasIsActor()) {
- size += com.google.protobuf.CodedOutputStream
- .computeBoolSize(8, getIsActor());
+ .computeMessageSize(3, getActorInfo());
}
if (hasIsOneWay()) {
size += com.google.protobuf.CodedOutputStream
- .computeBoolSize(9, getIsOneWay());
+ .computeBoolSize(4, getIsOneWay());
}
- if (hasIsEscaped()) {
+ if (hasSupervisorUuid()) {
size += com.google.protobuf.CodedOutputStream
- .computeBoolSize(10, getIsEscaped());
+ .computeStringSize(5, getSupervisorUuid());
}
if (hasSender()) {
size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(11, getSender());
+ .computeMessageSize(6, getSender());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
@@ -2208,29 +3063,14 @@ public final class RemoteProtocol {
if (other.hasMessage()) {
mergeMessage(other.getMessage());
}
- if (other.hasMethod()) {
- setMethod(other.getMethod());
- }
- if (other.hasTarget()) {
- setTarget(other.getTarget());
- }
- if (other.hasUuid()) {
- setUuid(other.getUuid());
- }
- if (other.hasTimeout()) {
- setTimeout(other.getTimeout());
- }
- if (other.hasSupervisorUuid()) {
- setSupervisorUuid(other.getSupervisorUuid());
- }
- if (other.hasIsActor()) {
- setIsActor(other.getIsActor());
+ if (other.hasActorInfo()) {
+ mergeActorInfo(other.getActorInfo());
}
if (other.hasIsOneWay()) {
setIsOneWay(other.getIsOneWay());
}
- if (other.hasIsEscaped()) {
- setIsEscaped(other.getIsEscaped());
+ if (other.hasSupervisorUuid()) {
+ setSupervisorUuid(other.getSupervisorUuid());
}
if (other.hasSender()) {
mergeSender(other.getSender());
@@ -2274,38 +3114,23 @@ public final class RemoteProtocol {
break;
}
case 26: {
- setMethod(input.readString());
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.Builder subBuilder = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.newBuilder();
+ if (hasActorInfo()) {
+ subBuilder.mergeFrom(getActorInfo());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setActorInfo(subBuilder.buildPartial());
break;
}
- case 34: {
- setTarget(input.readString());
- break;
- }
- case 42: {
- setUuid(input.readString());
- break;
- }
- case 48: {
- setTimeout(input.readUInt64());
- break;
- }
- case 58: {
- setSupervisorUuid(input.readString());
- break;
- }
- case 64: {
- setIsActor(input.readBool());
- break;
- }
- case 72: {
+ case 32: {
setIsOneWay(input.readBool());
break;
}
- case 80: {
- setIsEscaped(input.readBool());
+ case 42: {
+ setSupervisorUuid(input.readString());
break;
}
- case 90: {
+ case 50: {
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol.Builder subBuilder = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteActorRefProtocol.newBuilder();
if (hasSender()) {
subBuilder.mergeFrom(getSender());
@@ -2374,88 +3199,62 @@ public final class RemoteProtocol {
return this;
}
- // optional string method = 3;
- public boolean hasMethod() {
- return result.hasMethod();
+ // required .ActorInfoProtocol actorInfo = 3;
+ public boolean hasActorInfo() {
+ return result.hasActorInfo();
}
- public java.lang.String getMethod() {
- return result.getMethod();
+ public se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol getActorInfo() {
+ return result.getActorInfo();
}
- public Builder setMethod(java.lang.String value) {
+ public Builder setActorInfo(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol value) {
if (value == null) {
- throw new NullPointerException();
- }
- result.hasMethod = true;
- result.method_ = value;
+ throw new NullPointerException();
+ }
+ result.hasActorInfo = true;
+ result.actorInfo_ = value;
return this;
}
- public Builder clearMethod() {
- result.hasMethod = false;
- result.method_ = getDefaultInstance().getMethod();
+ public Builder setActorInfo(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.Builder builderForValue) {
+ result.hasActorInfo = true;
+ result.actorInfo_ = builderForValue.build();
+ return this;
+ }
+ public Builder mergeActorInfo(se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol value) {
+ if (result.hasActorInfo() &&
+ result.actorInfo_ != se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.getDefaultInstance()) {
+ result.actorInfo_ =
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.newBuilder(result.actorInfo_).mergeFrom(value).buildPartial();
+ } else {
+ result.actorInfo_ = value;
+ }
+ result.hasActorInfo = true;
+ return this;
+ }
+ public Builder clearActorInfo() {
+ result.hasActorInfo = false;
+ result.actorInfo_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.getDefaultInstance();
return this;
}
- // required string target = 4;
- public boolean hasTarget() {
- return result.hasTarget();
+ // required bool isOneWay = 4;
+ public boolean hasIsOneWay() {
+ return result.hasIsOneWay();
}
- public java.lang.String getTarget() {
- return result.getTarget();
+ public boolean getIsOneWay() {
+ return result.getIsOneWay();
}
- public Builder setTarget(java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- result.hasTarget = true;
- result.target_ = value;
+ public Builder setIsOneWay(boolean value) {
+ result.hasIsOneWay = true;
+ result.isOneWay_ = value;
return this;
}
- public Builder clearTarget() {
- result.hasTarget = false;
- result.target_ = getDefaultInstance().getTarget();
+ public Builder clearIsOneWay() {
+ result.hasIsOneWay = false;
+ result.isOneWay_ = false;
return this;
}
- // required string uuid = 5;
- public boolean hasUuid() {
- return result.hasUuid();
- }
- public java.lang.String getUuid() {
- return result.getUuid();
- }
- public Builder setUuid(java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- result.hasUuid = true;
- result.uuid_ = value;
- return this;
- }
- public Builder clearUuid() {
- result.hasUuid = false;
- result.uuid_ = getDefaultInstance().getUuid();
- return this;
- }
-
- // required uint64 timeout = 6;
- public boolean hasTimeout() {
- return result.hasTimeout();
- }
- public long getTimeout() {
- return result.getTimeout();
- }
- public Builder setTimeout(long value) {
- result.hasTimeout = true;
- result.timeout_ = value;
- return this;
- }
- public Builder clearTimeout() {
- result.hasTimeout = false;
- result.timeout_ = 0L;
- return this;
- }
-
- // optional string supervisorUuid = 7;
+ // optional string supervisorUuid = 5;
public boolean hasSupervisorUuid() {
return result.hasSupervisorUuid();
}
@@ -2476,61 +3275,7 @@ public final class RemoteProtocol {
return this;
}
- // required bool isActor = 8;
- public boolean hasIsActor() {
- return result.hasIsActor();
- }
- public boolean getIsActor() {
- return result.getIsActor();
- }
- public Builder setIsActor(boolean value) {
- result.hasIsActor = true;
- result.isActor_ = value;
- return this;
- }
- public Builder clearIsActor() {
- result.hasIsActor = false;
- result.isActor_ = false;
- return this;
- }
-
- // required bool isOneWay = 9;
- public boolean hasIsOneWay() {
- return result.hasIsOneWay();
- }
- public boolean getIsOneWay() {
- return result.getIsOneWay();
- }
- public Builder setIsOneWay(boolean value) {
- result.hasIsOneWay = true;
- result.isOneWay_ = value;
- return this;
- }
- public Builder clearIsOneWay() {
- result.hasIsOneWay = false;
- result.isOneWay_ = false;
- return this;
- }
-
- // required bool isEscaped = 10;
- public boolean hasIsEscaped() {
- return result.hasIsEscaped();
- }
- public boolean getIsEscaped() {
- return result.getIsEscaped();
- }
- public Builder setIsEscaped(boolean value) {
- result.hasIsEscaped = true;
- result.isEscaped_ = value;
- return this;
- }
- public Builder clearIsEscaped() {
- result.hasIsEscaped = false;
- result.isEscaped_ = false;
- return this;
- }
-
- // optional .RemoteActorRefProtocol sender = 11;
+ // optional .RemoteActorRefProtocol sender = 6;
public boolean hasSender() {
return result.hasSender();
}
@@ -3168,6 +3913,20 @@ public final class RemoteProtocol {
public boolean hasPostRestart() { return hasPostRestart; }
public java.lang.String getPostRestart() { return postRestart_; }
+ // optional string init = 4;
+ public static final int INIT_FIELD_NUMBER = 4;
+ private boolean hasInit;
+ private java.lang.String init_ = "";
+ public boolean hasInit() { return hasInit; }
+ public java.lang.String getInit() { return init_; }
+
+ // optional string shutdown = 5;
+ public static final int SHUTDOWN_FIELD_NUMBER = 5;
+ private boolean hasShutdown;
+ private java.lang.String shutdown_ = "";
+ public boolean hasShutdown() { return hasShutdown; }
+ public java.lang.String getShutdown() { return shutdown_; }
+
private void initFields() {
lifeCycle_ = se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleType.PERMANENT;
}
@@ -3188,6 +3947,12 @@ public final class RemoteProtocol {
if (hasPostRestart()) {
output.writeString(3, getPostRestart());
}
+ if (hasInit()) {
+ output.writeString(4, getInit());
+ }
+ if (hasShutdown()) {
+ output.writeString(5, getShutdown());
+ }
getUnknownFields().writeTo(output);
}
@@ -3209,6 +3974,14 @@ public final class RemoteProtocol {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(3, getPostRestart());
}
+ if (hasInit()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(4, getInit());
+ }
+ if (hasShutdown()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(5, getShutdown());
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -3376,6 +4149,12 @@ public final class RemoteProtocol {
if (other.hasPostRestart()) {
setPostRestart(other.getPostRestart());
}
+ if (other.hasInit()) {
+ setInit(other.getInit());
+ }
+ if (other.hasShutdown()) {
+ setShutdown(other.getShutdown());
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -3419,6 +4198,14 @@ public final class RemoteProtocol {
setPostRestart(input.readString());
break;
}
+ case 34: {
+ setInit(input.readString());
+ break;
+ }
+ case 42: {
+ setShutdown(input.readString());
+ break;
+ }
}
}
}
@@ -3487,6 +4274,48 @@ public final class RemoteProtocol {
return this;
}
+ // optional string init = 4;
+ public boolean hasInit() {
+ return result.hasInit();
+ }
+ public java.lang.String getInit() {
+ return result.getInit();
+ }
+ public Builder setInit(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasInit = true;
+ result.init_ = value;
+ return this;
+ }
+ public Builder clearInit() {
+ result.hasInit = false;
+ result.init_ = getDefaultInstance().getInit();
+ return this;
+ }
+
+ // optional string shutdown = 5;
+ public boolean hasShutdown() {
+ return result.hasShutdown();
+ }
+ public java.lang.String getShutdown() {
+ return result.getShutdown();
+ }
+ public Builder setShutdown(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasShutdown = true;
+ result.shutdown_ = value;
+ return this;
+ }
+ public Builder clearShutdown() {
+ result.hasShutdown = false;
+ result.shutdown_ = getDefaultInstance().getShutdown();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:LifeCycleProtocol)
}
@@ -4173,6 +5002,16 @@ public final class RemoteProtocol {
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_MessageProtocol_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_ActorInfoProtocol_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_ActorInfoProtocol_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_TypedActorInfoProtocol_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_TypedActorInfoProtocol_fieldAccessorTable;
private static com.google.protobuf.Descriptors.Descriptor
internal_static_RemoteRequestProtocol_descriptor;
private static
@@ -4210,40 +5049,46 @@ public final class RemoteProtocol {
"\n\024RemoteProtocol.proto\"v\n\026RemoteActorRef" +
"Protocol\022\014\n\004uuid\030\001 \002(\t\022\026\n\016actorClassname" +
"\030\002 \002(\t\022%\n\013homeAddress\030\003 \002(\0132\020.AddressPro" +
- "tocol\022\017\n\007timeout\030\004 \001(\004\"\350\002\n\032SerializedAct" +
+ "tocol\022\017\n\007timeout\030\004 \001(\004\"\200\003\n\032SerializedAct" +
"orRefProtocol\022\014\n\004uuid\030\001 \002(\t\022\n\n\002id\030\002 \002(\t\022" +
"\026\n\016actorClassname\030\003 \002(\t\022)\n\017originalAddre" +
"ss\030\004 \002(\0132\020.AddressProtocol\022\025\n\ractorInsta" +
"nce\030\005 \001(\014\022\033\n\023serializerClassname\030\006 \001(\t\022\024" +
- "\n\014isTransactor\030\007 \001(\010\022\017\n\007timeout\030\010 \001(\004\022%\n" +
- "\tlifeCycle\030\t \001(\0132\022.LifeCycleProtocol\022+\n\n",
- "supervisor\030\n \001(\0132\027.RemoteActorRefProtoco" +
- "l\022\024\n\014hotswapStack\030\013 \001(\014\022(\n\010messages\030\014 \003(" +
- "\0132\026.RemoteRequestProtocol\"r\n\017MessageProt" +
- "ocol\0225\n\023serializationScheme\030\001 \002(\0162\030.Seri" +
- "alizationSchemeType\022\017\n\007message\030\002 \002(\014\022\027\n\017" +
- "messageManifest\030\003 \001(\014\"\374\001\n\025RemoteRequestP" +
- "rotocol\022\n\n\002id\030\001 \002(\004\022!\n\007message\030\002 \002(\0132\020.M" +
- "essageProtocol\022\016\n\006method\030\003 \001(\t\022\016\n\006target" +
- "\030\004 \002(\t\022\014\n\004uuid\030\005 \002(\t\022\017\n\007timeout\030\006 \002(\004\022\026\n" +
- "\016supervisorUuid\030\007 \001(\t\022\017\n\007isActor\030\010 \002(\010\022\020",
- "\n\010isOneWay\030\t \002(\010\022\021\n\tisEscaped\030\n \002(\010\022\'\n\006s" +
- "ender\030\013 \001(\0132\027.RemoteActorRefProtocol\"\252\001\n" +
- "\023RemoteReplyProtocol\022\n\n\002id\030\001 \002(\004\022!\n\007mess" +
- "age\030\002 \001(\0132\020.MessageProtocol\022%\n\texception" +
- "\030\003 \001(\0132\022.ExceptionProtocol\022\026\n\016supervisor" +
- "Uuid\030\004 \001(\t\022\017\n\007isActor\030\005 \002(\010\022\024\n\014isSuccess" +
- "ful\030\006 \002(\010\"_\n\021LifeCycleProtocol\022!\n\tlifeCy" +
- "cle\030\001 \002(\0162\016.LifeCycleType\022\022\n\npreRestart\030" +
- "\002 \001(\t\022\023\n\013postRestart\030\003 \001(\t\"1\n\017AddressPro" +
- "tocol\022\020\n\010hostname\030\001 \002(\t\022\014\n\004port\030\002 \002(\r\"7\n",
- "\021ExceptionProtocol\022\021\n\tclassname\030\001 \002(\t\022\017\n" +
- "\007message\030\002 \002(\t*]\n\027SerializationSchemeTyp" +
- "e\022\010\n\004JAVA\020\001\022\013\n\007SBINARY\020\002\022\016\n\nSCALA_JSON\020\003" +
- "\022\r\n\tJAVA_JSON\020\004\022\014\n\010PROTOBUF\020\005*-\n\rLifeCyc" +
- "leType\022\r\n\tPERMANENT\020\001\022\r\n\tTEMPORARY\020\002B-\n)" +
- "se.scalablesolutions.akka.remote.protoco" +
- "lH\001"
+ "\n\014isTransactor\030\007 \001(\010\022\017\n\007timeout\030\010 \001(\004\022\026\n" +
+ "\016receiveTimeout\030\t \001(\004\022%\n\tlifeCycle\030\n \001(\013",
+ "2\022.LifeCycleProtocol\022+\n\nsupervisor\030\013 \001(\013" +
+ "2\027.RemoteActorRefProtocol\022\024\n\014hotswapStac" +
+ "k\030\014 \001(\014\022(\n\010messages\030\r \003(\0132\026.RemoteReques" +
+ "tProtocol\"r\n\017MessageProtocol\0225\n\023serializ" +
+ "ationScheme\030\001 \002(\0162\030.SerializationSchemeT" +
+ "ype\022\017\n\007message\030\002 \002(\014\022\027\n\017messageManifest\030" +
+ "\003 \001(\014\"\222\001\n\021ActorInfoProtocol\022\014\n\004uuid\030\001 \002(" +
+ "\t\022\016\n\006target\030\002 \002(\t\022\017\n\007timeout\030\003 \002(\004\022\035\n\tac" +
+ "torType\030\004 \002(\0162\n.ActorType\022/\n\016typedActorI" +
+ "nfo\030\005 \001(\0132\027.TypedActorInfoProtocol\";\n\026Ty",
+ "pedActorInfoProtocol\022\021\n\tinterface\030\001 \002(\t\022" +
+ "\016\n\006method\030\002 \002(\t\"\300\001\n\025RemoteRequestProtoco" +
+ "l\022\n\n\002id\030\001 \002(\004\022!\n\007message\030\002 \002(\0132\020.Message" +
+ "Protocol\022%\n\tactorInfo\030\003 \002(\0132\022.ActorInfoP" +
+ "rotocol\022\020\n\010isOneWay\030\004 \002(\010\022\026\n\016supervisorU" +
+ "uid\030\005 \001(\t\022\'\n\006sender\030\006 \001(\0132\027.RemoteActorR" +
+ "efProtocol\"\252\001\n\023RemoteReplyProtocol\022\n\n\002id" +
+ "\030\001 \002(\004\022!\n\007message\030\002 \001(\0132\020.MessageProtoco" +
+ "l\022%\n\texception\030\003 \001(\0132\022.ExceptionProtocol" +
+ "\022\026\n\016supervisorUuid\030\004 \001(\t\022\017\n\007isActor\030\005 \002(",
+ "\010\022\024\n\014isSuccessful\030\006 \002(\010\"\177\n\021LifeCycleProt" +
+ "ocol\022!\n\tlifeCycle\030\001 \002(\0162\016.LifeCycleType\022" +
+ "\022\n\npreRestart\030\002 \001(\t\022\023\n\013postRestart\030\003 \001(\t" +
+ "\022\014\n\004init\030\004 \001(\t\022\020\n\010shutdown\030\005 \001(\t\"1\n\017Addr" +
+ "essProtocol\022\020\n\010hostname\030\001 \002(\t\022\014\n\004port\030\002 " +
+ "\002(\r\"7\n\021ExceptionProtocol\022\021\n\tclassname\030\001 " +
+ "\002(\t\022\017\n\007message\030\002 \002(\t*=\n\tActorType\022\017\n\013SCA" +
+ "LA_ACTOR\020\001\022\016\n\nJAVA_ACTOR\020\002\022\017\n\013TYPED_ACTO" +
+ "R\020\003*]\n\027SerializationSchemeType\022\010\n\004JAVA\020\001" +
+ "\022\013\n\007SBINARY\020\002\022\016\n\nSCALA_JSON\020\003\022\r\n\tJAVA_JS",
+ "ON\020\004\022\014\n\010PROTOBUF\020\005*-\n\rLifeCycleType\022\r\n\tP" +
+ "ERMANENT\020\001\022\r\n\tTEMPORARY\020\002B-\n)se.scalable" +
+ "solutions.akka.remote.protocolH\001"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -4263,7 +5108,7 @@ public final class RemoteProtocol {
internal_static_SerializedActorRefProtocol_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_SerializedActorRefProtocol_descriptor,
- new java.lang.String[] { "Uuid", "Id", "ActorClassname", "OriginalAddress", "ActorInstance", "SerializerClassname", "IsTransactor", "Timeout", "LifeCycle", "Supervisor", "HotswapStack", "Messages", },
+ new java.lang.String[] { "Uuid", "Id", "ActorClassname", "OriginalAddress", "ActorInstance", "SerializerClassname", "IsTransactor", "Timeout", "ReceiveTimeout", "LifeCycle", "Supervisor", "HotswapStack", "Messages", },
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.SerializedActorRefProtocol.class,
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.SerializedActorRefProtocol.Builder.class);
internal_static_MessageProtocol_descriptor =
@@ -4274,16 +5119,32 @@ public final class RemoteProtocol {
new java.lang.String[] { "SerializationScheme", "Message", "MessageManifest", },
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.MessageProtocol.class,
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.MessageProtocol.Builder.class);
- internal_static_RemoteRequestProtocol_descriptor =
+ internal_static_ActorInfoProtocol_descriptor =
getDescriptor().getMessageTypes().get(3);
+ internal_static_ActorInfoProtocol_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_ActorInfoProtocol_descriptor,
+ new java.lang.String[] { "Uuid", "Target", "Timeout", "ActorType", "TypedActorInfo", },
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.class,
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.ActorInfoProtocol.Builder.class);
+ internal_static_TypedActorInfoProtocol_descriptor =
+ getDescriptor().getMessageTypes().get(4);
+ internal_static_TypedActorInfoProtocol_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_TypedActorInfoProtocol_descriptor,
+ new java.lang.String[] { "Interface", "Method", },
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.class,
+ se.scalablesolutions.akka.remote.protocol.RemoteProtocol.TypedActorInfoProtocol.Builder.class);
+ internal_static_RemoteRequestProtocol_descriptor =
+ getDescriptor().getMessageTypes().get(5);
internal_static_RemoteRequestProtocol_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_RemoteRequestProtocol_descriptor,
- new java.lang.String[] { "Id", "Message", "Method", "Target", "Uuid", "Timeout", "SupervisorUuid", "IsActor", "IsOneWay", "IsEscaped", "Sender", },
+ new java.lang.String[] { "Id", "Message", "ActorInfo", "IsOneWay", "SupervisorUuid", "Sender", },
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol.class,
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol.Builder.class);
internal_static_RemoteReplyProtocol_descriptor =
- getDescriptor().getMessageTypes().get(4);
+ getDescriptor().getMessageTypes().get(6);
internal_static_RemoteReplyProtocol_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_RemoteReplyProtocol_descriptor,
@@ -4291,15 +5152,15 @@ public final class RemoteProtocol {
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteReplyProtocol.class,
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteReplyProtocol.Builder.class);
internal_static_LifeCycleProtocol_descriptor =
- getDescriptor().getMessageTypes().get(5);
+ getDescriptor().getMessageTypes().get(7);
internal_static_LifeCycleProtocol_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_LifeCycleProtocol_descriptor,
- new java.lang.String[] { "LifeCycle", "PreRestart", "PostRestart", },
+ new java.lang.String[] { "LifeCycle", "PreRestart", "PostRestart", "Init", "Shutdown", },
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleProtocol.class,
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.LifeCycleProtocol.Builder.class);
internal_static_AddressProtocol_descriptor =
- getDescriptor().getMessageTypes().get(6);
+ getDescriptor().getMessageTypes().get(8);
internal_static_AddressProtocol_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_AddressProtocol_descriptor,
@@ -4307,7 +5168,7 @@ public final class RemoteProtocol {
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.AddressProtocol.class,
se.scalablesolutions.akka.remote.protocol.RemoteProtocol.AddressProtocol.Builder.class);
internal_static_ExceptionProtocol_descriptor =
- getDescriptor().getMessageTypes().get(7);
+ getDescriptor().getMessageTypes().get(9);
internal_static_ExceptionProtocol_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_ExceptionProtocol_descriptor,
diff --git a/akka-core/src/main/protocol/RemoteProtocol.proto b/akka-core/src/main/protocol/RemoteProtocol.proto
index 6d8b8995f4..6cf9bfd534 100644
--- a/akka-core/src/main/protocol/RemoteProtocol.proto
+++ b/akka-core/src/main/protocol/RemoteProtocol.proto
@@ -36,10 +36,11 @@ message SerializedActorRefProtocol {
optional string serializerClassname = 6;
optional bool isTransactor = 7;
optional uint64 timeout = 8;
- optional LifeCycleProtocol lifeCycle = 9;
- optional RemoteActorRefProtocol supervisor = 10;
- optional bytes hotswapStack = 11;
- repeated RemoteRequestProtocol messages = 12;
+ optional uint64 receiveTimeout = 9;
+ optional LifeCycleProtocol lifeCycle = 10;
+ optional RemoteActorRefProtocol supervisor = 11;
+ optional bytes hotswapStack = 12;
+ repeated RemoteRequestProtocol messages = 13;
}
/**
@@ -51,21 +52,35 @@ message MessageProtocol {
optional bytes messageManifest = 3;
}
+/**
+ * Defines the actor info.
+ */
+message ActorInfoProtocol {
+ required string uuid = 1;
+ required string target = 2;
+ required uint64 timeout = 3;
+ required ActorType actorType = 4;
+ optional TypedActorInfoProtocol typedActorInfo = 5;
+}
+
+/**
+ * Defines the typed actor extra info.
+ */
+message TypedActorInfoProtocol {
+ required string interface = 1;
+ required string method = 2;
+}
+
/**
* Defines a remote message request.
*/
message RemoteRequestProtocol {
required uint64 id = 1;
required MessageProtocol message = 2;
- optional string method = 3;
- required string target = 4;
- required string uuid = 5;
- required uint64 timeout = 6;
- optional string supervisorUuid = 7;
- required bool isActor = 8;
- required bool isOneWay = 9;
- required bool isEscaped = 10;
- optional RemoteActorRefProtocol sender = 11;
+ required ActorInfoProtocol actorInfo = 3;
+ required bool isOneWay = 4;
+ optional string supervisorUuid = 5;
+ optional RemoteActorRefProtocol sender = 6;
}
/**
@@ -80,6 +95,15 @@ message RemoteReplyProtocol {
required bool isSuccessful = 6;
}
+/**
+ * Defines the actor type.
+ */
+enum ActorType {
+ SCALA_ACTOR = 1;
+ JAVA_ACTOR = 2;
+ TYPED_ACTOR = 3;
+}
+
/**
* Defines the serialization scheme used to serialize the message and/or Actor instance.
*/
@@ -114,8 +138,6 @@ enum DispatcherType {
*/
message LifeCycleProtocol {
required LifeCycleType lifeCycle = 1;
- optional string preRestart = 2;
- optional string postRestart = 3;
}
/**
diff --git a/akka-core/src/main/resources/META-INF/aop.xml b/akka-core/src/main/resources/META-INF/aop.xml
index 2f8d5159a8..bdc167ca54 100644
--- a/akka-core/src/main/resources/META-INF/aop.xml
+++ b/akka-core/src/main/resources/META-INF/aop.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/akka-core/src/main/scala/actor/ActiveObject.scala b/akka-core/src/main/scala/actor/ActiveObject.scala
deleted file mode 100644
index a545f9f633..0000000000
--- a/akka-core/src/main/scala/actor/ActiveObject.scala
+++ /dev/null
@@ -1,860 +0,0 @@
-/**
- * Copyright (C) 2009-2010 Scalable Solutions AB
- */
-
-package se.scalablesolutions.akka.actor
-
-import Actor._
-import se.scalablesolutions.akka.config.FaultHandlingStrategy
-import se.scalablesolutions.akka.remote.protocol.RemoteProtocol.RemoteRequestProtocol
-import se.scalablesolutions.akka.remote.{MessageSerializer, RemoteClient, RemoteRequestProtocolIdFactory}
-import se.scalablesolutions.akka.dispatch.{MessageDispatcher, Future, CompletableFuture}
-import se.scalablesolutions.akka.config.ScalaConfig._
-import se.scalablesolutions.akka.serialization.Serializer
-import se.scalablesolutions.akka.util._
-
-import org.codehaus.aspectwerkz.joinpoint.{MethodRtti, JoinPoint}
-import org.codehaus.aspectwerkz.proxy.Proxy
-import org.codehaus.aspectwerkz.annotation.{Aspect, Around}
-
-import java.net.InetSocketAddress
-import java.lang.reflect.{InvocationTargetException, Method}
-
-object Annotations {
- import se.scalablesolutions.akka.actor.annotation._
- val transactionrequired = classOf[transactionrequired]
- val prerestart = classOf[prerestart]
- val postrestart = classOf[postrestart]
- val shutdown = classOf[shutdown]
- val inittransactionalstate = classOf[inittransactionalstate]
-}
-
-/**
- * Configuration factory for Active Objects.
- *
- * FIXDOC: document ActiveObjectConfiguration
- */
-final class ActiveObjectConfiguration {
- private[akka] var _timeout: Long = Actor.TIMEOUT
- private[akka] var _restartCallbacks: Option[RestartCallbacks] = None
- private[akka] var _shutdownCallback: Option[ShutdownCallback] = None
- private[akka] var _transactionRequired = false
- private[akka] var _host: Option[InetSocketAddress] = None
- private[akka] var _messageDispatcher: Option[MessageDispatcher] = None
-
- def timeout(timeout: Long) : ActiveObjectConfiguration = {
- _timeout = timeout
- this
- }
-
- def restartCallbacks(pre: String, post: String) : ActiveObjectConfiguration = {
- _restartCallbacks = Some(new RestartCallbacks(pre, post))
- this
- }
-
- def shutdownCallback(down: String) : ActiveObjectConfiguration = {
- _shutdownCallback = Some(new ShutdownCallback(down))
- this
- }
-
- def makeTransactionRequired() : ActiveObjectConfiguration = {
- _transactionRequired = true;
- this
- }
-
- def makeRemote(hostname: String, port: Int) : ActiveObjectConfiguration = {
- _host = Some(new InetSocketAddress(hostname, port))
- this
- }
-
- def dispatcher(messageDispatcher: MessageDispatcher) : ActiveObjectConfiguration = {
- _messageDispatcher = Some(messageDispatcher)
- this
- }
-}
-
-/**
- * Holds RTTI (runtime type information) for the Active Object, f.e. current 'sender'
- * reference, the 'senderFuture' reference etc.
- *
- * In order to make use of this context you have to create a member field in your
- * Active Object that has the type 'ActiveObjectContext', then an instance will
- * be injected for you to use.
- *
- * This class does not contain static information but is updated by the runtime system
- * at runtime.
- *
- * Here is an example of usage:
- *
- * class Ping {
- * // This context will be injected, holds RTTI (runtime type information)
- * // for the current message send
- * private ActiveObjectContext context = null;
- *
- * public void hit(int count) {
- * Pong pong = (Pong) context.getSender();
- * pong.hit(count++)
- * }
- * }
- *
- *
- * @author Jonas Bonér
- */
-final class ActiveObjectContext {
- private[akka] var _sender: AnyRef = _
- private[akka] var _senderFuture: CompletableFuture[Any] = _
-
- /**
- * Returns the current sender Active Object reference.
- * Scala style getter.
- */
- def sender: AnyRef = {
- if (_sender eq null) throw new IllegalActorStateException("Sender reference should not be null.")
- else _sender
- }
-
- /**
- * Returns the current sender Active Object reference.
- * Java style getter.
- */
- def getSender: AnyRef = {
- if (_sender eq null) throw new IllegalActorStateException("Sender reference should not be null.")
- else _sender
- }
-
- /**
- * Returns the current sender future Active Object reference.
- * Scala style getter.
- */
- def senderFuture: Option[CompletableFuture[Any]] = if (_senderFuture eq null) None else Some(_senderFuture)
-
- /**
- * Returns the current sender future Active Object reference.
- * Java style getter.
- * This method returns 'null' if the sender future is not available.
- */
- def getSenderFuture = _senderFuture
-}
-
-/**
- * Internal helper class to help pass the contextual information between threads.
- *
- * @author Jonas Bonér
- */
-private[akka] object ActiveObjectContext {
- import scala.util.DynamicVariable
- private[actor] val sender = new DynamicVariable[AnyRef](null)
- private[actor] val senderFuture = new DynamicVariable[CompletableFuture[Any]](null)
-}
-
-/**
- * Factory class for creating Active Objects out of plain POJOs and/or POJOs with interfaces.
- *
- * @author Jonas Bonér
- */
-object ActiveObject extends Logging {
- import Actor.actorOf
-
- val AKKA_CAMEL_ROUTING_SCHEME = "akka"
- private[actor] val AW_PROXY_PREFIX = "$$ProxiedByAW".intern
-
- def newInstance[T](target: Class[T], timeout: Long): T =
- newInstance(target, actorOf(new Dispatcher(false)), None, timeout)
-
- def newInstance[T](target: Class[T]): T =
- newInstance(target, actorOf(new Dispatcher(false)), None, Actor.TIMEOUT)
-
- def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long): T =
- newInstance(intf, target, actorOf(new Dispatcher(false)), None, timeout)
-
- def newInstance[T](intf: Class[T], target: AnyRef): T =
- newInstance(intf, target, actorOf(new Dispatcher(false)), None, Actor.TIMEOUT)
-
- def newRemoteInstance[T](target: Class[T], timeout: Long, hostname: String, port: Int): T =
- newInstance(target, actorOf(new Dispatcher(false)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- def newRemoteInstance[T](target: Class[T], hostname: String, port: Int): T =
- newInstance(target, actorOf(new Dispatcher(false)), Some(new InetSocketAddress(hostname, port)), Actor.TIMEOUT)
-
- def newInstance[T](target: Class[T], config: ActiveObjectConfiguration): T = {
- val actor = actorOf(new Dispatcher(config._transactionRequired, config._restartCallbacks, config._shutdownCallback))
- if (config._messageDispatcher.isDefined) {
- actor.dispatcher = config._messageDispatcher.get
- }
- newInstance(target, actor, config._host, config._timeout)
- }
-
- def newInstance[T](intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration): T = {
- val actor = actorOf(new Dispatcher(config._transactionRequired, config._restartCallbacks, config._shutdownCallback))
- if (config._messageDispatcher.isDefined) {
- actor.dispatcher = config._messageDispatcher.get
- }
- newInstance(intf, target, actor, config._host, config._timeout)
- }
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newInstance[T](target: Class[T], timeout: Long, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(target, actorOf(new Dispatcher(false, restartCallbacks)), None, timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(intf, target, actorOf(new Dispatcher(false, restartCallbacks)), None, timeout)
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean): T =
- newInstance(target, actorOf(new Dispatcher(transactionRequired, None)), None, timeout)
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(target, actorOf(new Dispatcher(transactionRequired, restartCallbacks)), None, timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean): T =
- newInstance(intf, target, actorOf(new Dispatcher(transactionRequired, None)), None, timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(intf, target, actorOf(new Dispatcher(transactionRequired, restartCallbacks)), None, timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, hostname: String, port: Int): T =
- newInstance(intf, target, actorOf(new Dispatcher(false, None)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(intf, target, actorOf(new Dispatcher(false, restartCallbacks)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, hostname: String, port: Int): T =
- newInstance(target, actorOf(new Dispatcher(transactionRequired, None)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(target, actorOf(new Dispatcher(transactionRequired, restartCallbacks)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean, hostname: String, port: Int): T =
- newInstance(intf, target, actorOf(new Dispatcher(transactionRequired, None)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, transactionRequired: Boolean, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T =
- newInstance(intf, target, actorOf(new Dispatcher(transactionRequired, restartCallbacks)), Some(new InetSocketAddress(hostname, port)), timeout)
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher): T = {
- val actor = actorOf(new Dispatcher(false, None))
- actor.dispatcher = dispatcher
- newInstance(target, actor, None, timeout)
- }
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = {
- val actor = actorOf(new Dispatcher(false, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(target, actor, None, timeout)
- }
-
- @deprecated("use newInstance(intf: Class[T], target: AnyRef, config: ActiveObjectConfiguration) instead")
- def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher): T = {
- val actor = actorOf(new Dispatcher(false, None))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, None, timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(false, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, None, timeout)
- }
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newInstance[T](target: Class[T], timeout: Long, transactionRequired: Boolean, dispatcher: MessageDispatcher): T = {
- val actor = actorOf(new Dispatcher(transactionRequired, None))
- actor.dispatcher = dispatcher
- newInstance(target, actor, None, timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(transactionRequired, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(target, actor, None, timeout)
- }
-
- @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): T = {
- val actor = actorOf(new Dispatcher(transactionRequired, None))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, None, timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(transactionRequired, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, None, timeout)
- }
-
- @deprecated("use newInstance(target: Class[T], config: ActiveObjectConfiguration) instead")
- def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int): T = {
- val actor = actorOf(new Dispatcher(false, None))
- actor.dispatcher = dispatcher
- newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(false, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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): T = {
- val actor = actorOf(new Dispatcher(false, None))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(false, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(transactionRequired, None))
- actor.dispatcher = dispatcher
- newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(transactionRequired, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(transactionRequired, None))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- @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 = {
- val actor = actorOf(new Dispatcher(transactionRequired, restartCallbacks))
- actor.dispatcher = dispatcher
- newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout)
- }
-
- private[akka] def newInstance[T](target: Class[T], actorRef: ActorRef, remoteAddress: Option[InetSocketAddress], timeout: Long): T = {
- val proxy = Proxy.newInstance(target, true, false)
- val context = injectActiveObjectContext(proxy)
- actorRef.actor.asInstanceOf[Dispatcher].initialize(target, proxy, context)
- actorRef.timeout = timeout
- if (remoteAddress.isDefined) actorRef.makeRemote(remoteAddress.get)
- AspectInitRegistry.register(proxy, AspectInit(target, actorRef, remoteAddress, timeout))
- actorRef.start
- proxy.asInstanceOf[T]
- }
-
- private[akka] def newInstance[T](intf: Class[T], target: AnyRef, actorRef: ActorRef,
- remoteAddress: Option[InetSocketAddress], timeout: Long): T = {
- val context = injectActiveObjectContext(target)
- val proxy = Proxy.newInstance(Array(intf), Array(target), true, false)
- actorRef.actor.asInstanceOf[Dispatcher].initialize(target.getClass, target, context)
- actorRef.timeout = timeout
- if (remoteAddress.isDefined) actorRef.makeRemote(remoteAddress.get)
- AspectInitRegistry.register(proxy, AspectInit(intf, actorRef, remoteAddress, timeout))
- actorRef.start
- proxy.asInstanceOf[T]
- }
-
- def stop(obj: AnyRef): Unit = {
- val init = AspectInitRegistry.initFor(obj)
- init.actorRef.stop
- }
-
- /**
- * Get the underlying dispatcher actor for the given active object.
- */
- def actorFor(obj: AnyRef): Option[ActorRef] =
- ActorRegistry.actorsFor(classOf[Dispatcher]).find(a => a.actor.asInstanceOf[Dispatcher].target == Some(obj))
-
- /**
- * Links an other active object to this active object.
- * @param supervisor the supervisor active object
- * @param supervised the active object to link
- */
- def link(supervisor: AnyRef, supervised: AnyRef) = {
- val supervisorActor = actorFor(supervisor).getOrElse(
- throw new IllegalActorStateException("Can't link when the supervisor is not an active object"))
- val supervisedActor = actorFor(supervised).getOrElse(
- throw new IllegalActorStateException("Can't link when the supervised is not an active object"))
- supervisorActor.link(supervisedActor)
- }
-
- /**
- * Links an other active object to this active object and sets the fault handling for the supervisor.
- * @param supervisor the supervisor active object
- * @param supervised the active object to link
- * @param handler fault handling strategy
- * @param trapExceptions array of exceptions that should be handled by the supervisor
- */
- def link(supervisor: AnyRef, supervised: AnyRef, handler: FaultHandlingStrategy, trapExceptions: Array[Class[_ <: Throwable]]) = {
- val supervisorActor = actorFor(supervisor).getOrElse(
- throw new IllegalActorStateException("Can't link when the supervisor is not an active object"))
- val supervisedActor = actorFor(supervised).getOrElse(
- throw new IllegalActorStateException("Can't link when the supervised is not an active object"))
- supervisorActor.trapExit = trapExceptions.toList
- supervisorActor.faultHandler = Some(handler)
- supervisorActor.link(supervisedActor)
- }
-
- /**
- * Unlink the supervised active object from the supervisor.
- * @param supervisor the supervisor active object
- * @param supervised the active object to unlink
- */
- def unlink(supervisor: AnyRef, supervised: AnyRef) = {
- val supervisorActor = actorFor(supervisor).getOrElse(
- throw new IllegalActorStateException("Can't unlink when the supervisor is not an active object"))
- val supervisedActor = actorFor(supervised).getOrElse(
- throw new IllegalActorStateException("Can't unlink when the supervised is not an active object"))
- supervisorActor.unlink(supervisedActor)
- }
-
- /**
- * Sets the trap exit for the given supervisor active object.
- * @param supervisor the supervisor active object
- * @param trapExceptions array of exceptions that should be handled by the supervisor
- */
- def trapExit(supervisor: AnyRef, trapExceptions: Array[Class[_ <: Throwable]]) = {
- val supervisorActor = actorFor(supervisor).getOrElse(
- throw new IllegalActorStateException("Can't set trap exceptions when the supervisor is not an active object"))
- supervisorActor.trapExit = trapExceptions.toList
- this
- }
-
- /**
- * Sets the fault handling strategy for the given supervisor active object.
- * @param supervisor the supervisor active object
- * @param handler fault handling strategy
- */
- def faultHandler(supervisor: AnyRef, handler: FaultHandlingStrategy) = {
- val supervisorActor = actorFor(supervisor).getOrElse(
- throw new IllegalActorStateException("Can't set fault handler when the supervisor is not an active object"))
- supervisorActor.faultHandler = Some(handler)
- this
- }
-
- private def injectActiveObjectContext(activeObject: AnyRef): Option[ActiveObjectContext] = {
- def injectActiveObjectContext0(activeObject: AnyRef, clazz: Class[_]): Option[ActiveObjectContext] = {
- val contextField = clazz.getDeclaredFields.toList.find(_.getType == classOf[ActiveObjectContext])
- if (contextField.isDefined) {
- contextField.get.setAccessible(true)
- val context = new ActiveObjectContext
- contextField.get.set(activeObject, context)
- Some(context)
- } else {
- val parent = clazz.getSuperclass
- if (parent != null) injectActiveObjectContext0(activeObject, parent)
- else {
- log.trace(
- "Can't set 'ActiveObjectContext' for ActiveObject [%s] since no field of this type could be found.",
- activeObject.getClass.getName)
- None
- }
- }
- }
- injectActiveObjectContext0(activeObject, activeObject.getClass)
- }
-
- private[akka] def supervise(restartStrategy: RestartStrategy, components: List[Supervise]): Supervisor =
- Supervisor(SupervisorConfig(restartStrategy, components))
-
-}
-
-private[akka] object AspectInitRegistry extends ListenerManagement {
- private val initializations = new java.util.concurrent.ConcurrentHashMap[AnyRef, AspectInit]
-
- def initFor(target: AnyRef) = {
- initializations.get(target)
- }
-
- def register(target: AnyRef, init: AspectInit) = {
- val res = initializations.put(target, init)
- foreachListener(_ ! AspectInitRegistered(target, init))
- res
- }
-
- def unregister(target: AnyRef) = {
- val res = initializations.remove(target)
- foreachListener(_ ! AspectInitUnregistered(target, res))
- res
- }
-}
-
-private[akka] sealed trait AspectInitRegistryEvent
-private[akka] case class AspectInitRegistered(proxy: AnyRef, init: AspectInit) extends AspectInitRegistryEvent
-private[akka] case class AspectInitUnregistered(proxy: AnyRef, init: AspectInit) extends AspectInitRegistryEvent
-
-private[akka] sealed case class AspectInit(
- val target: Class[_],
- val actorRef: ActorRef,
- val remoteAddress: Option[InetSocketAddress],
- val timeout: Long) {
- def this(target: Class[_], actorRef: ActorRef, timeout: Long) = this(target, actorRef, None, timeout)
-}
-
-/**
- * AspectWerkz Aspect that is turning POJOs into Active Object.
- * Is deployed on a 'per-instance' basis.
- *
- * @author Jonas Bonér
- */
-@Aspect("perInstance")
-private[akka] sealed class ActiveObjectAspect {
- @volatile private var isInitialized = false
- @volatile private var isStopped = false
- private var target: Class[_] = _
- private var actorRef: ActorRef = _
- private var remoteAddress: Option[InetSocketAddress] = _
- private var timeout: Long = _
- @volatile private var instance: AnyRef = _
-
- @Around("execution(* *.*(..))")
- def invoke(joinPoint: JoinPoint): AnyRef = {
- if (!isInitialized) {
- val init = AspectInitRegistry.initFor(joinPoint.getThis)
- target = init.target
- actorRef = init.actorRef
- remoteAddress = init.remoteAddress
- timeout = init.timeout
- isInitialized = true
-
- }
- dispatch(joinPoint)
- }
-
- private def dispatch(joinPoint: JoinPoint) = {
- if (remoteAddress.isDefined) remoteDispatch(joinPoint)
- else localDispatch(joinPoint)
- }
-
- private def localDispatch(joinPoint: JoinPoint): AnyRef = {
- val rtti = joinPoint.getRtti.asInstanceOf[MethodRtti]
- val isOneWay = isVoid(rtti)
- val sender = ActiveObjectContext.sender.value
- val senderFuture = ActiveObjectContext.senderFuture.value
-
- if (!actorRef.isRunning && !isStopped) {
- isStopped = true
- joinPoint.proceed
- } else if (isOneWay) {
- actorRef ! Invocation(joinPoint, true, true, sender, senderFuture)
- null.asInstanceOf[AnyRef]
- } else {
- val result = (actorRef !! (Invocation(joinPoint, false, isOneWay, sender, senderFuture), timeout)).as[AnyRef]
- if (result.isDefined) result.get
- else throw new IllegalActorStateException("No result defined for invocation [" + joinPoint + "]")
- }
- }
-
- private def remoteDispatch(joinPoint: JoinPoint): AnyRef = {
- val rtti = joinPoint.getRtti.asInstanceOf[MethodRtti]
- val isOneWay = isVoid(rtti)
- val (message: Array[AnyRef], isEscaped) = escapeArguments(rtti.getParameterValues)
- val requestBuilder = RemoteRequestProtocol.newBuilder
- .setId(RemoteRequestProtocolIdFactory.nextId)
- .setMessage(MessageSerializer.serialize(message))
- .setMethod(rtti.getMethod.getName)
- .setTarget(target.getName)
- .setUuid(actorRef.uuid)
- .setTimeout(timeout)
- .setIsActor(false)
- .setIsOneWay(isOneWay)
- .setIsEscaped(false)
- val id = actorRef.registerSupervisorAsRemoteActor
- if (id.isDefined) requestBuilder.setSupervisorUuid(id.get)
- val remoteMessage = requestBuilder.build
- val future = RemoteClient.clientFor(remoteAddress.get).send(remoteMessage, None)
- if (isOneWay) null // for void methods
- else {
- if (future.isDefined) {
- future.get.await
- val result = getResultOrThrowException(future.get)
- if (result.isDefined) result.get
- else throw new IllegalActorStateException("No result returned from call to [" + joinPoint + "]")
- } else throw new IllegalActorStateException("No future returned from call to [" + joinPoint + "]")
- }
- }
-
- private def getResultOrThrowException[T](future: Future[T]): Option[T] =
- if (future.exception.isDefined) {
- val (_, cause) = future.exception.get
- throw cause
- } else future.result
-
- private def isVoid(rtti: MethodRtti) = rtti.getMethod.getReturnType == java.lang.Void.TYPE
-
- private def escapeArguments(args: Array[AnyRef]): Tuple2[Array[AnyRef], Boolean] = {
- var isEscaped = false
- val escapedArgs = for (arg <- args) yield {
- val clazz = arg.getClass
- if (clazz.getName.contains(ActiveObject.AW_PROXY_PREFIX)) {
- isEscaped = true
- ActiveObject.AW_PROXY_PREFIX + clazz.getSuperclass.getName
- } else arg
- }
- (escapedArgs, isEscaped)
- }
-}
-
-/**
- * Represents a snapshot of the current invocation.
- *
- * @author Jonas Bonér
- */
-@serializable private[akka] case class Invocation(
- joinPoint: JoinPoint, isOneWay: Boolean, isVoid: Boolean, sender: AnyRef, senderFuture: CompletableFuture[Any]) {
-
- override def toString: String = synchronized {
- "Invocation [joinPoint: " + joinPoint.toString +
- ", isOneWay: " + isOneWay +
- ", isVoid: " + isVoid +
- ", sender: " + sender +
- ", senderFuture: " + senderFuture +
- "]"
- }
-
- override def hashCode: Int = synchronized {
- var result = HashCode.SEED
- result = HashCode.hash(result, joinPoint)
- result = HashCode.hash(result, isOneWay)
- result = HashCode.hash(result, isVoid)
- result = HashCode.hash(result, sender)
- result = HashCode.hash(result, senderFuture)
- result
- }
-
- override def equals(that: Any): Boolean = synchronized {
- that != null &&
- that.isInstanceOf[Invocation] &&
- that.asInstanceOf[Invocation].joinPoint == joinPoint &&
- that.asInstanceOf[Invocation].isOneWay == isOneWay &&
- that.asInstanceOf[Invocation].isVoid == isVoid &&
- that.asInstanceOf[Invocation].sender == sender &&
- that.asInstanceOf[Invocation].senderFuture == senderFuture
- }
-}
-
-object Dispatcher {
- val ZERO_ITEM_CLASS_ARRAY = Array[Class[_]]()
- val ZERO_ITEM_OBJECT_ARRAY = Array[Object]()
- var crashedActorTl:ThreadLocal[Dispatcher] = new ThreadLocal();
-}
-
-/**
- * Generic Actor managing Invocation dispatch, transaction and error management.
- *
- * @author Jonas Bonér
- */
-private[akka] class Dispatcher(transactionalRequired: Boolean,
- var restartCallbacks: Option[RestartCallbacks] = None,
- var shutdownCallback: Option[ShutdownCallback] = None) extends Actor {
- import Dispatcher._
-
- private[actor] var target: Option[AnyRef] = None
- private var zhutdown: Option[Method] = None
- private var preRestart: Option[Method] = None
- private var postRestart: Option[Method] = None
- private var initTxState: Option[Method] = None
- private var context: Option[ActiveObjectContext] = None
- private var targetClass:Class[_] = _
-
-
-
- def this(transactionalRequired: Boolean) = this(transactionalRequired,None)
-
- private[actor] def initialize(targetClass: Class[_], targetInstance: AnyRef, ctx: Option[ActiveObjectContext]) = {
-
- if (transactionalRequired || targetClass.isAnnotationPresent(Annotations.transactionrequired))
- self.makeTransactionRequired
- self.id = targetClass.getName
- this.targetClass = targetClass
- target = Some(targetInstance)
- context = ctx
- val methods = targetInstance.getClass.getDeclaredMethods.toList
-
- // See if we have any config define restart callbacks
- restartCallbacks match {
- case None => {}
- case Some(RestartCallbacks(pre, post)) =>
- preRestart = Some(try {
- targetInstance.getClass.getDeclaredMethod(pre, ZERO_ITEM_CLASS_ARRAY: _*)
- } catch { case e => throw new IllegalActorStateException(
- "Could not find pre restart method [" + pre + "] \nin [" +
- targetClass.getName + "]. \nIt must have a zero argument definition.") })
- postRestart = Some(try {
- targetInstance.getClass.getDeclaredMethod(post, ZERO_ITEM_CLASS_ARRAY: _*)
- } catch { case e => throw new IllegalActorStateException(
- "Could not find post restart method [" + post + "] \nin [" +
- targetClass.getName + "]. \nIt must have a zero argument definition.") })
- }
- // See if we have any config define a shutdown callback
- shutdownCallback match {
- case None => {}
- case Some(ShutdownCallback(down)) =>
- zhutdown = Some(try {
- targetInstance.getClass.getDeclaredMethod(down, ZERO_ITEM_CLASS_ARRAY: _*)
- } catch { case e => throw new IllegalStateException(
- "Could not find shutdown method [" + down + "] \nin [" +
- targetClass.getName + "]. \nIt must have a zero argument definition.") })
- }
-
- // See if we have any annotation defined restart callbacks
- if (!preRestart.isDefined) preRestart = methods.find(m => m.isAnnotationPresent(Annotations.prerestart))
- if (!postRestart.isDefined) postRestart = methods.find(m => m.isAnnotationPresent(Annotations.postrestart))
- // See if we have an annotation defined shutdown callback
- if (!zhutdown.isDefined) zhutdown = methods.find(m => m.isAnnotationPresent(Annotations.shutdown))
-
- if (preRestart.isDefined && preRestart.get.getParameterTypes.length != 0)
- throw new IllegalActorStateException(
- "Method annotated with @prerestart or defined as a restart callback in \n[" +
- targetClass.getName + "] must have a zero argument definition")
- if (postRestart.isDefined && postRestart.get.getParameterTypes.length != 0)
- throw new IllegalActorStateException(
- "Method annotated with @postrestart or defined as a restart callback in \n[" +
- targetClass.getName + "] must have a zero argument definition")
- if (zhutdown.isDefined && zhutdown.get.getParameterTypes.length != 0)
- throw new IllegalStateException(
- "Method annotated with @shutdown or defined as a shutdown callback in \n[" +
- targetClass.getName + "] must have a zero argument definition")
-
- if (preRestart.isDefined) preRestart.get.setAccessible(true)
- if (postRestart.isDefined) postRestart.get.setAccessible(true)
- if (zhutdown.isDefined) zhutdown.get.setAccessible(true)
-
- // see if we have a method annotated with @inittransactionalstate, if so invoke it
- initTxState = methods.find(m => m.isAnnotationPresent(Annotations.inittransactionalstate))
- if (initTxState.isDefined && initTxState.get.getParameterTypes.length != 0)
- throw new IllegalActorStateException("Method annotated with @inittransactionalstate must have a zero argument definition")
- if (initTxState.isDefined) initTxState.get.setAccessible(true)
- }
-
- def receive = {
- case Invocation(joinPoint, isOneWay, _, sender, senderFuture) =>
- context.foreach { ctx =>
- if (sender ne null) ctx._sender = sender
- if (senderFuture ne null) ctx._senderFuture = senderFuture
- }
- ActiveObjectContext.sender.value = joinPoint.getThis // set next sender
- self.senderFuture.foreach(ActiveObjectContext.senderFuture.value = _)
-
- if (Actor.SERIALIZE_MESSAGES) serializeArguments(joinPoint)
- if (isOneWay) joinPoint.proceed
- else self.reply(joinPoint.proceed)
-
- // Jan Kronquist: started work on issue 121
- case Link(target) => self.link(target)
- case Unlink(target) => self.unlink(target)
- case unexpected =>
- throw new IllegalActorStateException("Unexpected message [" + unexpected + "] sent to [" + this + "]")
- }
-
- override def preRestart(reason: Throwable) {
- try {
- // Since preRestart is called we know that this dispatcher
- // is about to be restarted. Put the instance in a thread
- // local so the new dispatcher can be initialized with the contents of the
- // old.
- //FIXME - This should be considered as a workaround.
- crashedActorTl.set(this)
- if (preRestart.isDefined) preRestart.get.invoke(target.get, ZERO_ITEM_OBJECT_ARRAY: _*)
- } catch { case e: InvocationTargetException => throw e.getCause }
- }
-
- override def postRestart(reason: Throwable) {
- try {
-
- if (postRestart.isDefined) {
- postRestart.get.invoke(target.get, ZERO_ITEM_OBJECT_ARRAY: _*)
- }
- } catch { case e: InvocationTargetException => throw e.getCause }
- }
-
- override def init = {
- // Get the crashed dispatcher from thread local and intitialize this actor with the
- // contents of the old dispatcher
- val oldActor = crashedActorTl.get();
- if(oldActor != null) {
- initialize(oldActor.targetClass,oldActor.target.get,oldActor.context)
- crashedActorTl.set(null)
- }
- }
-
- override def shutdown = {
- try {
- if (zhutdown.isDefined) {
- zhutdown.get.invoke(target.get, ZERO_ITEM_OBJECT_ARRAY: _*)
- }
- } catch {
- case e: InvocationTargetException => throw e.getCause
- } finally {
- AspectInitRegistry.unregister(target.get);
- }
- }
-
- override def initTransactionalState = {
- try {
- if (initTxState.isDefined && target.isDefined) initTxState.get.invoke(target.get, ZERO_ITEM_OBJECT_ARRAY: _*)
- } catch { case e: InvocationTargetException => throw e.getCause }
- }
-
-
-
- private def serializeArguments(joinPoint: JoinPoint) = {
- val args = joinPoint.getRtti.asInstanceOf[MethodRtti].getParameterValues
- var unserializable = false
- var hasMutableArgument = false
- for (arg <- args.toList) {
- if (!arg.isInstanceOf[String] &&
- !arg.isInstanceOf[Byte] &&
- !arg.isInstanceOf[Int] &&
- !arg.isInstanceOf[Long] &&
- !arg.isInstanceOf[Float] &&
- !arg.isInstanceOf[Double] &&
- !arg.isInstanceOf[Boolean] &&
- !arg.isInstanceOf[Char] &&
- !arg.isInstanceOf[java.lang.Byte] &&
- !arg.isInstanceOf[java.lang.Integer] &&
- !arg.isInstanceOf[java.lang.Long] &&
- !arg.isInstanceOf[java.lang.Float] &&
- !arg.isInstanceOf[java.lang.Double] &&
- !arg.isInstanceOf[java.lang.Boolean] &&
- !arg.isInstanceOf[java.lang.Character]) {
- hasMutableArgument = true
- }
- if (arg.getClass.getName.contains(ActiveObject.AW_PROXY_PREFIX)) unserializable = true
- }
- if (!unserializable && hasMutableArgument) {
- val copyOfArgs = Serializer.Java.deepClone(args)
- joinPoint.getRtti.asInstanceOf[MethodRtti].setParameterValues(copyOfArgs.asInstanceOf[Array[AnyRef]])
- }
- }
-}
diff --git a/akka-core/src/main/scala/actor/Actor.scala b/akka-core/src/main/scala/actor/Actor.scala
index e1227168b2..5b736abb70 100644
--- a/akka-core/src/main/scala/actor/Actor.scala
+++ b/akka-core/src/main/scala/actor/Actor.scala
@@ -9,10 +9,12 @@ import se.scalablesolutions.akka.config.Config._
import se.scalablesolutions.akka.config.ScalaConfig._
import se.scalablesolutions.akka.serialization.Serializer
import se.scalablesolutions.akka.util.Helpers.{narrow, narrowSilently}
-import se.scalablesolutions.akka.util.Logging
+import se.scalablesolutions.akka.util.{Logging, Duration}
import com.google.protobuf.Message
+
import java.util.concurrent.TimeUnit
+import java.net.InetSocketAddress
/**
* Implements the Transactor abstraction. E.g. a transactional actor.
@@ -32,8 +34,9 @@ trait Transactor extends Actor {
*
* @author Jonas Bonér
*/
-abstract class RemoteActor(hostname: String, port: Int) extends Actor {
- self.makeRemote(hostname, port)
+abstract class RemoteActor(address: InetSocketAddress) extends Actor {
+ def this(hostname: String, port: Int) = this(new InetSocketAddress(hostname, port))
+ self.makeRemote(address)
}
/**
@@ -46,14 +49,16 @@ case class Exit(dead: ActorRef, killer: Throwable) extends LifeCycleMessage
case class Link(child: ActorRef) extends LifeCycleMessage
case class Unlink(child: ActorRef) extends LifeCycleMessage
case class UnlinkAndStop(child: ActorRef) extends LifeCycleMessage
-case object Kill extends LifeCycleMessage
case object ReceiveTimeout extends LifeCycleMessage
+case class MaximumNumberOfRestartsWithinTimeRangeReached(
+ victim: ActorRef, maxNrOfRetries: Int, withinTimeRange: Int, lastExceptionCausingRestart: Throwable) extends LifeCycleMessage
// Exceptions for Actors
class ActorStartException private[akka](message: String) extends RuntimeException(message)
class IllegalActorStateException 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)
+class ActorTimeoutException private[akka](message: String) extends RuntimeException(message)
/**
* Actor factory module with factory methods for creating various kinds of Actors.
@@ -61,7 +66,7 @@ class ActorInitializationException private[akka](message: String) extends Runtim
* @author Jonas Bonér
*/
object Actor extends Logging {
- val TIMEOUT = config.getInt("akka.actor.timeout", 5000)
+ val TIMEOUT = Duration(config.getInt("akka.actor.timeout", 5), TIME_UNIT).toMillis
val SERIALIZE_MESSAGES = config.getBool("akka.actor.serialize-messages", false)
/**
@@ -71,9 +76,9 @@ object Actor extends Logging {
type Receive = PartialFunction[Any, Unit]
private[actor] val actorRefInCreation = new scala.util.DynamicVariable[Option[ActorRef]](None)
-
+
/**
- * Creates a Actor.actorOf out of the Actor with type T.
+ * Creates an ActorRef out of the Actor with type T.
*
* import Actor._
* val actor = actorOf[MyActor]
@@ -89,7 +94,7 @@ object Actor extends Logging {
def actorOf[T <: Actor : Manifest]: ActorRef = new LocalActorRef(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]])
/**
- * Creates a Actor.actorOf out of the Actor. Allows you to pass in a factory function
+ * Creates an ActorRef 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.
*
@@ -284,6 +289,7 @@ object Actor extends Logging {
* @author Jonas Bonér
*/
trait Actor extends Logging {
+
/**
* Type alias because traits cannot have companion objects.
*/
@@ -300,12 +306,12 @@ trait Actor extends Logging {
Actor.actorRefInCreation.value = None
if (ref.isEmpty) throw new ActorInitializationException(
"ActorRef for instance of actor [" + getClass.getName + "] is not in scope." +
- "\n\tYou can not create an instance of an actor explicitly using 'new MyActor'." +
- "\n\tYou have to use one of the factory methods in the 'Actor' object to create a new actor." +
- "\n\tEither use:" +
- "\n\t\t'val actor = Actor.actorOf[MyActor]', or" +
- "\n\t\t'val actor = Actor.actorOf(new MyActor(..))', or" +
- "\n\t\t'val actor = Actor.actor { case msg => .. } }'")
+ "\n\tYou can not create an instance of an actor explicitly using 'new MyActor'." +
+ "\n\tYou have to use one of the factory methods in the 'Actor' object to create a new actor." +
+ "\n\tEither use:" +
+ "\n\t\t'val actor = Actor.actorOf[MyActor]', or" +
+ "\n\t\t'val actor = Actor.actorOf(new MyActor(..))', or" +
+ "\n\t\t'val actor = Actor.actor { case msg => .. } }'")
else ref
}
@@ -413,6 +419,14 @@ trait Actor extends Logging {
*/
def isDefinedAt(message: Any): Boolean = base.isDefinedAt(message)
+ /** One of the fundamental methods of the ActorsModel
+ * Actor assumes a new behavior
+ */
+ def become(behavior: Option[Receive]) {
+ self.hotswap = behavior
+ self.checkReceiveTimeout // FIXME : how to reschedule receivetimeout on hotswap?
+ }
+
// =========================================
// ==== INTERNAL IMPLEMENTATION DETAILS ====
// =========================================
@@ -425,13 +439,12 @@ trait Actor extends Logging {
}
private val lifeCycles: Receive = {
- case HotSwap(code) => self.hotswap = code; self.checkReceiveTimeout // FIXME : how to reschedule receivetimeout on hotswap?
- case Restart(reason) => self.restart(reason)
- case Exit(dead, reason) => self.handleTrapExit(dead, reason)
- case Link(child) => self.link(child)
- case Unlink(child) => self.unlink(child)
+ case HotSwap(code) => become(code)
+ case Exit(dead, reason) => self.handleTrapExit(dead, reason)
+ case Link(child) => self.link(child)
+ case Unlink(child) => self.unlink(child)
case UnlinkAndStop(child) => self.unlink(child); child.stop
- case Kill => throw new ActorKilledException("Actor [" + toString + "] was killed by a Kill message")
+ case Restart(reason) => throw reason
}
}
diff --git a/akka-core/src/main/scala/actor/ActorRef.scala b/akka-core/src/main/scala/actor/ActorRef.scala
index 2472ea924d..2fd205edeb 100644
--- a/akka-core/src/main/scala/actor/ActorRef.scala
+++ b/akka-core/src/main/scala/actor/ActorRef.scala
@@ -10,26 +10,27 @@ import se.scalablesolutions.akka.config.{AllForOneStrategy, OneForOneStrategy, F
import se.scalablesolutions.akka.config.ScalaConfig._
import se.scalablesolutions.akka.stm.global._
import se.scalablesolutions.akka.stm.TransactionManagement._
-import se.scalablesolutions.akka.stm.TransactionManagement
+import se.scalablesolutions.akka.stm.{TransactionManagement, TransactionSetAbortedException}
import se.scalablesolutions.akka.remote.protocol.RemoteProtocol._
import se.scalablesolutions.akka.remote.{RemoteNode, RemoteServer, RemoteClient, MessageSerializer, RemoteRequestProtocolIdFactory}
import se.scalablesolutions.akka.serialization.Serializer
import se.scalablesolutions.akka.util.{HashCode, Logging, UUID, ReentrantGuard}
+import RemoteActorSerialization._
import org.multiverse.api.ThreadLocalTransaction._
import org.multiverse.commitbarriers.CountDownCommitBarrier
-
-import jsr166x.{Deque, ConcurrentLinkedDeque}
+import org.multiverse.api.exceptions.DeadTransactionException
import java.net.InetSocketAddress
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.atomic.AtomicReference
+import java.util.concurrent.{ConcurrentHashMap, TimeUnit}
import java.util.{Map => JMap}
import java.lang.reflect.Field
-import RemoteActorSerialization._
+
+import jsr166x.{Deque, ConcurrentLinkedDeque}
import com.google.protobuf.ByteString
-import java.util.concurrent.{ConcurrentHashMap, TimeUnit}
/**
* ActorRef is an immutable and serializable handle to an Actor.
@@ -63,7 +64,7 @@ import java.util.concurrent.{ConcurrentHashMap, TimeUnit}
*
* @author Jonas Bonér
*/
-trait ActorRef extends TransactionManagement {
+trait ActorRef extends TransactionManagement with java.lang.Comparable[ActorRef] {
// Only mutable for RemoteServer in order to maintain identity across nodes
@volatile protected[akka] var _uuid = UUID.newUuid.toString
@@ -71,9 +72,7 @@ trait ActorRef extends TransactionManagement {
@volatile protected[this] var _isShutDown = false
@volatile protected[akka] var _isBeingRestarted = false
@volatile protected[akka] var _homeAddress = new InetSocketAddress(RemoteServer.HOSTNAME, RemoteServer.PORT)
-
@volatile protected[akka] var _timeoutActor: Option[ActorRef] = None
-
@volatile protected[akka] var startOnCreation = false
@volatile protected[akka] var registeredInRemoteNodeDuringSerialization = false
protected[this] val guard = new ReentrantGuard
@@ -99,12 +98,12 @@ trait ActorRef extends TransactionManagement {
@volatile var timeout: Long = Actor.TIMEOUT
/**
- * User overridable callback/setting.
- *
- * Defines the default timeout for an initial receive invocation.
- * When specified, the receive function should be able to handle a 'ReceiveTimeout' message.
- */
- @volatile var receiveTimeout: Option[Long] = None
+ * User overridable callback/setting.
+ *
+ * Defines the default timeout for an initial receive invocation.
+ * When specified, the receive function should be able to handle a 'ReceiveTimeout' message.
+ */
+ @volatile var receiveTimeout: Option[Long] = None
/**
* User overridable callback/setting.
@@ -166,12 +165,12 @@ trait ActorRef extends TransactionManagement {
* The default is also that all actors that are created and spawned from within this actor
* is sharing the same dispatcher as its creator.
*/
- private[akka] var _dispatcher: MessageDispatcher = Dispatchers.globalExecutorBasedEventDrivenDispatcher
+ @volatile private[akka] var _dispatcher: MessageDispatcher = Dispatchers.globalExecutorBasedEventDrivenDispatcher
/**
* Holds the hot swapped partial function.
*/
- protected[akka] var hotswap: Option[PartialFunction[Any, Unit]] = None // FIXME: _hotswap should be a stack
+ @volatile protected[akka] var hotswap: Option[PartialFunction[Any, Unit]] = None // FIXME: _hotswap should be a stack
/**
* User overridable callback/setting.
@@ -184,12 +183,12 @@ trait ActorRef extends TransactionManagement {
/**
* Configuration for TransactionFactory. User overridable.
*/
- protected[akka] var _transactionConfig: TransactionConfig = DefaultGlobalTransactionConfig
+ @volatile protected[akka] var _transactionConfig: TransactionConfig = DefaultGlobalTransactionConfig
/**
* TransactionFactory to be used for atomic when isTransactor. Configuration is overridable.
*/
- private[akka] var _transactionFactory: Option[TransactionFactory] = None
+ @volatile private[akka] var _transactionFactory: Option[TransactionFactory] = None
/**
* This lock ensures thread safety in the dispatching: only one message can
@@ -204,6 +203,10 @@ trait ActorRef extends TransactionManagement {
protected[akka] def currentMessage_=(msg: Option[MessageInvocation]) = guard.withGuard { _currentMessage = msg }
protected[akka] def currentMessage = guard.withGuard { _currentMessage }
+
+ /** comparison only takes uuid into account
+ */
+ def compareTo(other: ActorRef) = this.uuid.compareTo(other.uuid)
/**
* Returns the uuid for the actor.
@@ -215,12 +218,10 @@ trait ActorRef extends TransactionManagement {
* Is defined if the message was sent from another Actor, else None.
*/
def sender: Option[ActorRef] = {
- //Five lines of map-performance-avoidance, could be just: currentMessage map { _.sender }
+ // Five lines of map-performance-avoidance, could be just: currentMessage map { _.sender }
val msg = currentMessage
- if(msg.isEmpty)
- None
- else
- msg.get.sender
+ if(msg.isEmpty) None
+ else msg.get.sender
}
/**
@@ -228,12 +229,10 @@ trait ActorRef extends TransactionManagement {
* Is defined if the message was sent with sent with '!!' or '!!!', else None.
*/
def senderFuture: Option[CompletableFuture[Any]] = {
- //Five lines of map-performance-avoidance, could be just: currentMessage map { _.senderFuture }
+ // Five lines of map-performance-avoidance, could be just: currentMessage map { _.senderFuture }
val msg = currentMessage
- if(msg.isEmpty)
- None
- else
- msg.get.senderFuture
+ if(msg.isEmpty) None
+ else msg.get.senderFuture
}
/**
@@ -296,15 +295,15 @@ trait ActorRef extends TransactionManagement {
def !!(message: Any, timeout: Long = this.timeout)(implicit sender: Option[ActorRef] = None): Option[Any] = {
if (isRunning) {
val future = postMessageToMailboxAndCreateFutureResultWithTimeout[Any](message, timeout, sender, None)
- val isActiveObject = message.isInstanceOf[Invocation]
- if (isActiveObject && message.asInstanceOf[Invocation].isVoid) {
+ val isTypedActor = message.isInstanceOf[Invocation]
+ if (isTypedActor && message.asInstanceOf[Invocation].isVoid) {
future.asInstanceOf[CompletableFuture[Option[_]]].completeWithResult(None)
}
try {
future.await
} catch {
case e: FutureTimeoutException =>
- if (isActiveObject) throw e
+ if (isTypedActor) throw e
else None
}
if (future.exception.isDefined) throw future.exception.get._2
@@ -352,7 +351,7 @@ trait ActorRef extends TransactionManagement {
"\n\tNo sender in scope, can't reply. " +
"\n\tYou have probably: " +
"\n\t\t1. Sent a message to an Actor from an instance that is NOT an Actor." +
- "\n\t\t2. Invoked a method on an Active Object from an instance NOT an Active Object." +
+ "\n\t\t2. Invoked a method on an TypedActor from an instance NOT an TypedActor." +
"\n\tElse you might want to use 'reply_?' which returns Boolean(true) if succes and Boolean(false) if no sender in scope")
/**
@@ -421,13 +420,13 @@ trait ActorRef extends TransactionManagement {
* Returns the home address and port for this actor.
*/
def homeAddress: InetSocketAddress = _homeAddress
-
+
/**
* Set the home address and port for this actor.
*/
def homeAddress_=(hostnameAndPort: Tuple2[String, Int]): Unit =
homeAddress_=(new InetSocketAddress(hostnameAndPort._1, hostnameAndPort._2))
-
+
/**
* Set the home address and port for this actor.
*/
@@ -442,7 +441,7 @@ trait ActorRef extends TransactionManagement {
/**
* Starts up the actor and its message queue.
*/
- def start: ActorRef
+ def start(): ActorRef
/**
* Shuts down the actor its dispatcher and message queue.
@@ -462,64 +461,48 @@ trait ActorRef extends TransactionManagement {
* If the 'trapExit' member field has been set to at contain at least one exception class then it will
* 'trap' these exceptions and automatically restart the linked actors according to the restart strategy
* defined by the 'faultHandler'.
- *
- * To be invoked from within the actor itself.
*/
def link(actorRef: ActorRef): Unit
/**
* Unlink the actor.
- *
- * To be invoked from within the actor itself.
*/
def unlink(actorRef: ActorRef): Unit
/**
* Atomically start and link an actor.
- *
- * To be invoked from within the actor itself.
*/
def startLink(actorRef: ActorRef): Unit
/**
* Atomically start, link and make an actor remote.
- *
- * To be invoked from within the actor itself.
*/
def startLinkRemote(actorRef: ActorRef, hostname: String, port: Int): Unit
/**
* Atomically create (from actor class) and start an actor.
- *
- * To be invoked from within the actor itself.
*/
def spawn[T <: Actor : Manifest]: ActorRef
/**
* Atomically create (from actor class), start and make an actor remote.
- *
- * To be invoked from within the actor itself.
*/
def spawnRemote[T <: Actor: Manifest](hostname: String, port: Int): ActorRef
/**
* Atomically create (from actor class), start and link an actor.
- *
- * To be invoked from within the actor itself.
*/
def spawnLink[T <: Actor: Manifest]: ActorRef
/**
* Atomically create (from actor class), start, link and make an actor remote.
- *
- * To be invoked from within the actor itself.
*/
def spawnLinkRemote[T <: Actor : Manifest](hostname: String, port: Int): ActorRef
/**
* Returns the mailbox size.
*/
- def mailboxSize: Int
+ def mailboxSize = dispatcher.mailboxSize(this)
/**
* Returns the supervisor, if there is one.
@@ -547,13 +530,14 @@ trait ActorRef extends TransactionManagement {
protected[akka] def supervisor_=(sup: Option[ActorRef]): Unit
- protected[akka] def mailbox: Deque[MessageInvocation]
-
- protected[akka] def restart(reason: Throwable): Unit
+ protected[akka] def mailbox: AnyRef
+ protected[akka] def mailbox_=(value: AnyRef): AnyRef
protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit
- protected[akka] def restartLinkedActors(reason: Throwable): Unit
+ protected[akka] def restart(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit
+
+ protected[akka] def restartLinkedActors(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit
protected[akka] def registerSupervisorAsRemoteActor: Option[String]
@@ -571,23 +555,19 @@ trait ActorRef extends TransactionManagement {
override def toString = "Actor[" + id + ":" + uuid + "]"
- protected[akka] def cancelReceiveTimeout = {
- _timeoutActor.foreach {
- x =>
- if (x.isRunning) Scheduler.unschedule(x)
- _timeoutActor = None
- log.debug("Timeout canceled for %s", this)
- }
- }
-
- protected [akka] def checkReceiveTimeout = {
+ protected[akka] def checkReceiveTimeout = {
cancelReceiveTimeout
- receiveTimeout.foreach { timeout =>
+ receiveTimeout.foreach { time =>
log.debug("Scheduling timeout for %s", this)
- _timeoutActor = Some(Scheduler.scheduleOnce(this, ReceiveTimeout, timeout, TimeUnit.MILLISECONDS))
+ _timeoutActor = Some(Scheduler.scheduleOnce(this, ReceiveTimeout, time, TimeUnit.MILLISECONDS))
}
}
+ protected[akka] def cancelReceiveTimeout = _timeoutActor.foreach { timeoutActor =>
+ if (timeoutActor.isRunning) Scheduler.unschedule(timeoutActor)
+ _timeoutActor = None
+ log.debug("Timeout canceled for %s", this)
+ }
}
/**
@@ -595,12 +575,28 @@ trait ActorRef extends TransactionManagement {
*
* @author Jonas Bonér
*/
-sealed class LocalActorRef private[akka](
+class LocalActorRef private[akka](
private[this] var actorFactory: Either[Option[Class[_ <: Actor]], Option[() => Actor]] = Left(None))
extends ActorRef {
- private var isDeserialized = false
- private var loader: Option[ClassLoader] = None
+ @volatile private[akka] var _remoteAddress: Option[InetSocketAddress] = None // only mutable to maintain identity across nodes
+ @volatile private[akka] var _linkedActors: Option[ConcurrentHashMap[String, ActorRef]] = None
+ @volatile private[akka] var _supervisor: Option[ActorRef] = None
+ @volatile private var isInInitialization = false
+ @volatile private var runActorInitialization = false
+ @volatile private var isDeserialized = false
+ @volatile private var loader: Option[ClassLoader] = None
+ @volatile private var maxNrOfRetriesCount: Int = 0
+ @volatile private var restartsWithinTimeRangeTimestamp: Long = 0L
+ @volatile private var _mailbox: AnyRef = _
+
+ protected[this] val actorInstance = guard.withGuard { new AtomicReference[Actor](newActor) }
+
+ // Needed to be able to null out the 'val self: ActorRef' member variables to make the Actor
+ // instance elegible for garbage collection
+ private val actorSelfFields = findActorSelfField(actor.getClass)
+
+ if (runActorInitialization && !isDeserialized) initializeActorInstance
private[akka] def this(clazz: Class[_ <: Actor]) = this(Left(Some(clazz)))
private[akka] def this(factory: () => Actor) = this(Right(Some(factory)))
@@ -614,6 +610,7 @@ sealed class LocalActorRef private[akka](
__port: Int,
__isTransactor: Boolean,
__timeout: Long,
+ __receiveTimeout: Option[Long],
__lifeCycle: Option[LifeCycle],
__supervisor: Option[ActorRef],
__hotswap: Option[PartialFunction[Any, Unit]],
@@ -635,6 +632,7 @@ sealed class LocalActorRef private[akka](
homeAddress = (__hostname, __port)
isTransactor = __isTransactor
timeout = __timeout
+ receiveTimeout = __receiveTimeout
lifeCycle = __lifeCycle
_supervisor = __supervisor
hotswap = __hotswap
@@ -643,30 +641,11 @@ sealed class LocalActorRef private[akka](
actorSelfFields._3.set(actor, Some(this))
start
__messages.foreach(message => this ! MessageSerializer.deserialize(message.getMessage))
+ checkReceiveTimeout
ActorRegistry.register(this)
}
- // Only mutable for RemoteServer in order to maintain identity across nodes
- @volatile private[akka] var _remoteAddress: Option[InetSocketAddress] = None
- @volatile private[akka] var _linkedActors: Option[ConcurrentHashMap[String, ActorRef]] = None
- @volatile private[akka] var _supervisor: Option[ActorRef] = None
-
- protected[akka] val _mailbox: Deque[MessageInvocation] = new ConcurrentLinkedDeque[MessageInvocation]
- protected[this] val actorInstance = guard.withGuard { new AtomicReference[Actor](newActor) }
-
- @volatile private var isInInitialization = false
- @volatile private var runActorInitialization = false
-
- // Needed to be able to null out the 'val self: ActorRef' member variables to make the Actor
- // instance elegible for garbage collection
- private val actorSelfFields = findActorSelfField(actor.getClass)
-
- if (runActorInitialization && !isDeserialized) initializeActorInstance
-
- /**
- * Returns the mailbox.
- */
- def mailbox: Deque[MessageInvocation] = _mailbox
+ // ========= PUBLIC FUNCTIONS =========
/**
* Returns the class for the Actor instance that is managed by the ActorRef.
@@ -681,7 +660,7 @@ sealed class LocalActorRef private[akka](
/**
* Sets the dispatcher for this actor. Needs to be invoked before the actor is started.
*/
- def dispatcher_=(md: MessageDispatcher): Unit = guard.withGuard {
+ def dispatcher_=(md: MessageDispatcher): Unit = {
if (!isRunning || isBeingRestarted) _dispatcher = md
else throw new ActorInitializationException(
"Can not swap dispatcher for " + toString + " after it has been started")
@@ -690,7 +669,7 @@ sealed class LocalActorRef private[akka](
/**
* Get the dispatcher for this actor.
*/
- def dispatcher: MessageDispatcher = guard.withGuard { _dispatcher }
+ def dispatcher: MessageDispatcher = _dispatcher
/**
* Invoking 'makeRemote' means that an actor will be moved to and invoked on a remote host.
@@ -734,19 +713,19 @@ sealed class LocalActorRef private[akka](
/**
* Get the transaction configuration for this actor.
*/
- def transactionConfig: TransactionConfig = guard.withGuard { _transactionConfig }
+ def transactionConfig: TransactionConfig = _transactionConfig
/**
* Set the contact address for this actor. This is used for replying to messages
* sent asynchronously when no reply channel exists.
*/
- def homeAddress_=(address: InetSocketAddress): Unit = guard.withGuard { _homeAddress = address }
+ def homeAddress_=(address: InetSocketAddress): Unit = _homeAddress = address
/**
* Returns the remote address for the actor, if any, else None.
*/
- def remoteAddress: Option[InetSocketAddress] = guard.withGuard { _remoteAddress }
- protected[akka] def remoteAddress_=(addr: Option[InetSocketAddress]): Unit = guard.withGuard { _remoteAddress = addr }
+ def remoteAddress: Option[InetSocketAddress] = _remoteAddress
+ protected[akka] def remoteAddress_=(addr: Option[InetSocketAddress]): Unit = _remoteAddress = addr
/**
* Starts up the actor and its message queue.
@@ -783,7 +762,7 @@ sealed class LocalActorRef private[akka](
address.getHostName, address.getPort, uuid))
RemoteNode.unregister(this)
nullOutActorRefReferencesFor(actorInstance.get)
- } else if (isBeingRestarted) throw new ActorKilledException("Actor [" + toString + "] is being restarted.")
+ } //else if (isBeingRestarted) throw new ActorKilledException("Actor [" + toString + "] is being restarted.")
}
/**
@@ -898,19 +877,16 @@ sealed class LocalActorRef private[akka](
}
/**
- * Returns the mailbox size.
+ * Returns the mailbox.
*/
- def mailboxSize: Int = _mailbox.size
+ def mailbox: AnyRef = _mailbox
- /**
- * Returns a copy of all the messages, put into a List[MessageInvocation].
- */
- def messagesInMailbox: List[MessageInvocation] = _mailbox.toArray.toList.asInstanceOf[List[MessageInvocation]]
+ protected[akka] def mailbox_=(value: AnyRef):AnyRef = { _mailbox = value; value }
/**
* Shuts down and removes all linked actors.
*/
- def shutdownLinkedActors(): Unit = guard.withGuard {
+ def shutdownLinkedActors(): Unit = {
linkedActorsAsList.foreach(_.stop)
linkedActors.clear
}
@@ -918,9 +894,173 @@ sealed class LocalActorRef private[akka](
/**
* Returns the supervisor, if there is one.
*/
- def supervisor: Option[ActorRef] = guard.withGuard { _supervisor }
+ def supervisor: Option[ActorRef] = _supervisor
- protected[akka] def supervisor_=(sup: Option[ActorRef]): Unit = guard.withGuard { _supervisor = sup }
+ // ========= AKKA PROTECTED FUNCTIONS =========
+
+ protected[akka] def supervisor_=(sup: Option[ActorRef]): Unit = _supervisor = sup
+
+ protected[akka] def postMessageToMailbox(message: Any, senderOption: Option[ActorRef]): Unit = {
+ joinTransaction(message)
+
+ if (remoteAddress.isDefined) {
+ RemoteClient.clientFor(remoteAddress.get).send[Any](
+ createRemoteRequestProtocolBuilder(this, message, true, senderOption).build, None)
+ } else {
+ val invocation = new MessageInvocation(this, message, senderOption, None, transactionSet.get)
+ invocation.send
+ }
+ }
+
+ protected[akka] def postMessageToMailboxAndCreateFutureResultWithTimeout[T](
+ message: Any,
+ timeout: Long,
+ senderOption: Option[ActorRef],
+ senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T] = {
+ joinTransaction(message)
+
+ if (remoteAddress.isDefined) {
+ val future = RemoteClient.clientFor(remoteAddress.get).send(
+ createRemoteRequestProtocolBuilder(this, message, false, senderOption).build, senderFuture)
+ if (future.isDefined) future.get
+ else throw new IllegalActorStateException("Expected a future from remote call to actor " + toString)
+ } else {
+ val future = if (senderFuture.isDefined) senderFuture.get
+ else new DefaultCompletableFuture[T](timeout)
+ val invocation = new MessageInvocation(
+ this, message, senderOption, Some(future.asInstanceOf[CompletableFuture[Any]]), transactionSet.get)
+ invocation.send
+ future
+ }
+ }
+
+ /**
+ * Callback for the dispatcher. This is the ingle entry point to the user Actor implementation.
+ */
+ protected[akka] def invoke(messageHandle: MessageInvocation): Unit = guard.withGuard {
+ if (isShutdown)
+ Actor.log.warning("Actor [%s] is shut down,\n\tignoring message [%s]", toString, messageHandle)
+ else {
+ currentMessage = Option(messageHandle)
+ try {
+ dispatch(messageHandle)
+ } catch {
+ case e =>
+ Actor.log.error(e, "Could not invoke actor [%s]", this)
+ throw e
+ } finally {
+ currentMessage = None //TODO: Don't reset this, we might want to resend the message
+ }
+ }
+ }
+
+ protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit = {
+ if (trapExit.exists(_.isAssignableFrom(reason.getClass))) {
+ faultHandler match {
+ case Some(AllForOneStrategy(maxNrOfRetries, withinTimeRange)) =>
+ restartLinkedActors(reason, maxNrOfRetries, withinTimeRange)
+
+ case Some(OneForOneStrategy(maxNrOfRetries, withinTimeRange)) =>
+ dead.restart(reason, maxNrOfRetries, withinTimeRange)
+
+ case None => throw new IllegalActorStateException(
+ "No 'faultHandler' defined for an actor with the 'trapExit' member field defined " +
+ "\n\tto non-empty list of exception classes - can't proceed " + toString)
+ }
+ } else {
+ notifySupervisorWithMessage(Exit(this, reason)) // if 'trapExit' is not defined then pass the Exit on
+ }
+ }
+
+ protected[akka] def restart(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit = {
+ if (maxNrOfRetriesCount == 0) restartsWithinTimeRangeTimestamp = System.currentTimeMillis // first time around
+ maxNrOfRetriesCount += 1
+
+ val tooManyRestarts = maxNrOfRetriesCount > maxNrOfRetries
+ val restartingHasExpired = (System.currentTimeMillis - restartsWithinTimeRangeTimestamp) > withinTimeRange
+ if (tooManyRestarts || restartingHasExpired) {
+ val notification = MaximumNumberOfRestartsWithinTimeRangeReached(this, maxNrOfRetries, withinTimeRange, reason)
+ Actor.log.warning(
+ "Maximum number of restarts [%s] within time range [%s] reached." +
+ "\n\tWill *not* restart actor [%s] anymore." +
+ "\n\tLast exception causing restart was" +
+ "\n\t[%s].",
+ maxNrOfRetries, withinTimeRange, this, reason)
+ _supervisor.foreach { sup =>
+ // can supervisor handle the notification?
+ if (sup.isDefinedAt(notification)) notifySupervisorWithMessage(notification)
+ else Actor.log.warning(
+ "No message handler defined for system message [MaximumNumberOfRestartsWithinTimeRangeReached]" +
+ "\n\tCan't send the message to the supervisor [%s].", sup)
+ }
+ stop
+ } else {
+ _isBeingRestarted = true
+ val failedActor = actorInstance.get
+ guard.withGuard {
+ lifeCycle match {
+ case Some(LifeCycle(Temporary)) => shutDownTemporaryActor(this)
+ case _ =>
+ // either permanent or none where default is permanent
+ Actor.log.info("Restarting actor [%s] configured as PERMANENT.", id)
+ Actor.log.debug("Restarting linked actors for actor [%s].", id)
+ restartLinkedActors(reason, maxNrOfRetries, withinTimeRange)
+ Actor.log.debug("Invoking 'preRestart' for failed actor instance [%s].", id)
+ if (isTypedActorDispatcher(failedActor)) restartTypedActorDispatcher(failedActor, reason)
+ else restartActor(failedActor, reason)
+ _isBeingRestarted = false
+ }
+ }
+ }
+ }
+
+ protected[akka] def restartLinkedActors(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int) = {
+ linkedActorsAsList.foreach { actorRef =>
+ actorRef.lifeCycle match {
+ // either permanent or none where default is permanent
+ case Some(LifeCycle(Temporary)) => shutDownTemporaryActor(actorRef)
+ case _ => actorRef.restart(reason, maxNrOfRetries, withinTimeRange)
+ }
+ }
+ }
+
+ protected[akka] def registerSupervisorAsRemoteActor: Option[String] = guard.withGuard {
+ if (_supervisor.isDefined) {
+ RemoteClient.clientFor(remoteAddress.get).registerSupervisorForActor(this)
+ Some(_supervisor.get.uuid)
+ } else None
+ }
+
+ protected[akka] def linkedActors: JMap[String, ActorRef] = guard.withGuard {
+ if (_linkedActors.isEmpty) {
+ val actors = new ConcurrentHashMap[String, ActorRef]
+ _linkedActors = Some(actors)
+ actors
+ } else _linkedActors.get
+ }
+
+ protected[akka] def linkedActorsAsList: List[ActorRef] =
+ linkedActors.values.toArray.toList.asInstanceOf[List[ActorRef]]
+
+ // ========= PRIVATE FUNCTIONS =========
+
+ private def isTypedActorDispatcher(a: Actor): Boolean = a.isInstanceOf[Dispatcher]
+
+ private def restartTypedActorDispatcher(failedActor: Actor, reason: Throwable) = {
+ failedActor.preRestart(reason)
+ failedActor.postRestart(reason)
+ }
+
+ private def restartActor(failedActor: Actor, reason: Throwable) = {
+ failedActor.preRestart(reason)
+ nullOutActorRefReferencesFor(failedActor)
+ val freshActor = newActor
+ freshActor.init
+ freshActor.initTransactionalState
+ actorInstance.set(freshActor)
+ Actor.log.debug("Invoking 'postRestart' for new actor instance [%s].", id)
+ freshActor.postRestart(reason)
+ }
private def spawnButDoNotStart[T <: Actor: Manifest]: ActorRef = guard.withGuard {
val actorRef = Actor.actorOf(manifest[T].erasure.asInstanceOf[Class[T]].newInstance)
@@ -954,74 +1094,23 @@ sealed class LocalActorRef private[akka](
actor
}
- protected[akka] def postMessageToMailbox(message: Any, senderOption: Option[ActorRef]): Unit = {
- joinTransaction(message)
-
- if (remoteAddress.isDefined) {
- RemoteClient.clientFor(remoteAddress.get).send[Any](
- createRemoteRequestProtocolBuilder(this, message, true, senderOption).build, None)
- } else {
- val invocation = new MessageInvocation(this, message, senderOption, None, transactionSet.get)
- if (dispatcher.usesActorMailbox) {
- _mailbox.add(invocation)
- invocation.send
- } else invocation.send
- }
- }
-
- protected[akka] def postMessageToMailboxAndCreateFutureResultWithTimeout[T](
- message: Any,
- timeout: Long,
- senderOption: Option[ActorRef],
- senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T] = {
- joinTransaction(message)
-
- if (remoteAddress.isDefined) {
- val future = RemoteClient.clientFor(remoteAddress.get).send(
- createRemoteRequestProtocolBuilder(this, message, false, senderOption).build, senderFuture)
- if (future.isDefined) future.get
- else throw new IllegalActorStateException("Expected a future from remote call to actor " + toString)
- } else {
- val future = if (senderFuture.isDefined) senderFuture.get
- else new DefaultCompletableFuture[T](timeout)
- val invocation = new MessageInvocation(
- this, message, senderOption, Some(future.asInstanceOf[CompletableFuture[Any]]), transactionSet.get)
- if (dispatcher.usesActorMailbox) _mailbox.add(invocation)
- invocation.send
- future
- }
- }
-
private def joinTransaction(message: Any) = if (isTransactionSetInScope) {
import org.multiverse.api.ThreadLocalTransaction
- val txSet = getTransactionSetInScope
- Actor.log.trace("Joining transaction set [%s];\n\tactor %s\n\twith message [%s]", txSet, toString, message) // FIXME test to run bench without this trace call
+ val oldTxSet = getTransactionSetInScope
+ val currentTxSet = if (oldTxSet.isAborted || oldTxSet.isCommitted) {
+ clearTransactionSet
+ createNewTransactionSet
+ } else oldTxSet
+ Actor.log.ifTrace("Joining transaction set [" + currentTxSet +
+ "];\n\tactor " + toString +
+ "\n\twith message [" + message + "]")
val mtx = ThreadLocalTransaction.getThreadLocalTransaction
- if ((mtx eq null) || mtx.getStatus.isDead) txSet.incParties
- else txSet.incParties(mtx, 1)
- }
-
- /**
- * Callback for the dispatcher. This is the ingle entry point to the user Actor implementation.
- */
- protected[akka] def invoke(messageHandle: MessageInvocation): Unit = actor.synchronized {
- if (isShutdown) {
- Actor.log.warning("Actor [%s] is shut down, ignoring message [%s]", toString, messageHandle)
- return
- }
- currentMessage = Option(messageHandle)
- try {
- dispatch(messageHandle)
- } catch {
- case e =>
- Actor.log.error(e, "Could not invoke actor [%s]", this)
- throw e
- } finally {
- currentMessage = None //TODO: Don't reset this, we might want to resend the message
- }
+ if ((mtx eq null) || mtx.getStatus.isDead) currentTxSet.incParties
+ else currentTxSet.incParties(mtx, 1)
}
private def dispatch[T](messageHandle: MessageInvocation) = {
+ Actor.log.ifTrace("Invoking actor with message:\n" + messageHandle)
val message = messageHandle.message //serializeMessage(messageHandle.message)
var topLevelTransaction = false
val txSet: Option[CountDownCommitBarrier] =
@@ -1029,9 +1118,8 @@ sealed class LocalActorRef private[akka](
else {
topLevelTransaction = true // FIXME create a new internal atomic block that can wait for X seconds if top level tx
if (isTransactor) {
- Actor.log.trace(
- "Creating a new transaction set (top-level transaction)\n\tfor actor %s\n\twith message %s",
- toString, messageHandle)
+ Actor.log.ifTrace("Creating a new transaction set (top-level transaction)\n\tfor actor " + toString +
+ "\n\twith message " + messageHandle)
Some(createNewTransactionSet)
} else None
}
@@ -1050,93 +1138,18 @@ sealed class LocalActorRef private[akka](
setTransactionSet(txSet) // restore transaction set to allow atomic block to do commit
}
} catch {
- case e =>
- _isBeingRestarted = true
- // abort transaction set
- if (isTransactionSetInScope) {
- val txSet = getTransactionSetInScope
- Actor.log.debug("Aborting transaction set [%s]", txSet)
- txSet.abort
- }
- Actor.log.error(e, "Exception when invoking \n\tactor [%s] \n\twith message [%s]", this, message)
-
- senderFuture.foreach(_.completeWithException(this, e))
-
- clearTransaction
- 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
- if (_supervisor.isDefined) _supervisor.get ! Exit(this, e)
+ case e: DeadTransactionException =>
+ handleExceptionInDispatch(
+ new TransactionSetAbortedException("Transaction set has been aborted by another participant"),
+ message, topLevelTransaction)
+ case e: InterruptedException => {} // received message while actor is shutting down, ignore
+ case e => handleExceptionInDispatch(e, message, topLevelTransaction)
} finally {
clearTransaction
if (topLevelTransaction) clearTransactionSet
}
}
- protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit = {
- if (trapExit.exists(_.isAssignableFrom(reason.getClass))) {
- faultHandler match {
- // FIXME: implement support for maxNrOfRetries and withinTimeRange in RestartStrategy
- case Some(AllForOneStrategy(maxNrOfRetries, withinTimeRange)) =>
- restartLinkedActors(reason)
-
- case Some(OneForOneStrategy(maxNrOfRetries, withinTimeRange)) =>
- dead.restart(reason)
-
- case None =>
- throw new IllegalActorStateException(
- "No 'faultHandler' defined for an actor with the 'trapExit' member field defined " +
- "\n\tto non-empty list of exception classes - can't proceed " + toString)
- }
- } else {
- if (lifeCycle.isEmpty) lifeCycle = Some(LifeCycle(Permanent)) // when passing on make sure we have a lifecycle
- _supervisor.foreach(_ ! Exit(this, reason)) // if 'trapExit' is not defined then pass the Exit on
- }
- }
-
- protected[akka] def restart(reason: Throwable): Unit = {
- val failedActor = actorInstance.get
- failedActor.synchronized {
- lifeCycle.get match {
- case LifeCycle(scope, _, _) => {
- scope match {
- case Permanent =>
- Actor.log.info("Restarting actor [%s] configured as PERMANENT.", id)
- restartLinkedActors(reason)
- Actor.log.debug("Restarting linked actors for actor [%s].", id)
- Actor.log.debug("Invoking 'preRestart' for failed actor instance [%s].", id)
- failedActor.preRestart(reason)
- nullOutActorRefReferencesFor(failedActor)
- val freshActor = newActor
- freshActor.synchronized {
- freshActor.init
- freshActor.initTransactionalState
- actorInstance.set(freshActor)
- Actor.log.debug("Invoking 'postRestart' for new actor instance [%s].", id)
- freshActor.postRestart(reason)
- }
- _isBeingRestarted = false
- case Temporary => shutDownTemporaryActor(this)
- }
- }
- }
- }
- }
-
- protected[akka] def restartLinkedActors(reason: Throwable) = guard.withGuard {
- linkedActorsAsList.foreach { actorRef =>
- if (actorRef.lifeCycle.isEmpty) actorRef.lifeCycle = Some(LifeCycle(Permanent))
- actorRef.lifeCycle.get match {
- case LifeCycle(scope, _, _) => {
- scope match {
- case Permanent => actorRef.restart(reason)
- case Temporary => shutDownTemporaryActor(actorRef)
- }
- }
- }
- }
- }
-
private def shutDownTemporaryActor(temporaryActor: ActorRef) = {
Actor.log.info("Actor [%s] configured as TEMPORARY and will not be restarted.", temporaryActor.id)
temporaryActor.stop
@@ -1147,28 +1160,41 @@ sealed class LocalActorRef private[akka](
"All linked actors have died permanently (they were all configured as TEMPORARY)" +
"\n\tshutting down and unlinking supervisor actor as well [%s].",
temporaryActor.id)
- _supervisor.foreach(_ ! UnlinkAndStop(this))
+ notifySupervisorWithMessage(UnlinkAndStop(this))
}
}
- protected[akka] def registerSupervisorAsRemoteActor: Option[String] = guard.withGuard {
- if (_supervisor.isDefined) {
- RemoteClient.clientFor(remoteAddress.get).registerSupervisorForActor(this)
- Some(_supervisor.get.uuid)
- } else None
+ private def handleExceptionInDispatch(reason: Throwable, message: Any, topLevelTransaction: Boolean) = {
+ Actor.log.error(reason, "Exception when invoking \n\tactor [%s] \n\twith message [%s]", this, message)
+
+ _isBeingRestarted = true
+ // abort transaction set
+ if (isTransactionSetInScope) {
+ val txSet = getTransactionSetInScope
+ if (!txSet.isCommitted) {
+ Actor.log.debug("Aborting transaction set [%s]", txSet)
+ txSet.abort
+ }
+ }
+
+ senderFuture.foreach(_.completeWithException(this, reason))
+
+ clearTransaction
+ if (topLevelTransaction) clearTransactionSet
+
+ notifySupervisorWithMessage(Exit(this, reason))
}
- protected[akka] def linkedActors: JMap[String, ActorRef] = guard.withGuard {
- if (_linkedActors.isEmpty) {
- val actors = new ConcurrentHashMap[String, ActorRef]
- _linkedActors = Some(actors)
- actors
- } else _linkedActors.get
+ private def notifySupervisorWithMessage(notification: LifeCycleMessage) = {
+ // FIXME to fix supervisor restart of remote actor for oneway calls, inject a supervisor proxy that can send notification back to client
+ _supervisor.foreach { sup =>
+ if (sup.isShutdown) { // if supervisor is shut down, game over for all linked actors
+// shutdownLinkedActors
+// stop
+ } else sup ! notification // else notify supervisor
+ }
}
- protected[akka] def linkedActorsAsList: List[ActorRef] =
- linkedActors.values.toArray.toList.asInstanceOf[List[ActorRef]]
-
private def nullOutActorRefReferencesFor(actor: Actor) = {
actorSelfFields._1.set(actor, null)
actorSelfFields._2.set(actor, null)
@@ -1188,7 +1214,8 @@ sealed class LocalActorRef private[akka](
case e: NoSuchFieldException =>
val parent = clazz.getSuperclass
if (parent != null) findActorSelfField(parent)
- else throw new IllegalActorStateException(toString + " is not an Actor since it have not mixed in the 'Actor' trait")
+ else throw new IllegalActorStateException(
+ toString + " is not an Actor since it have not mixed in the 'Actor' trait")
}
}
@@ -1293,13 +1320,13 @@ private[akka] case class RemoteActorRef private[akka] (
def spawnRemote[T <: Actor: Manifest](hostname: String, port: Int): ActorRef = unsupported
def spawnLink[T <: Actor: Manifest]: ActorRef = unsupported
def spawnLinkRemote[T <: Actor : Manifest](hostname: String, port: Int): ActorRef = unsupported
- def mailboxSize: Int = unsupported
def supervisor: Option[ActorRef] = unsupported
def shutdownLinkedActors: Unit = unsupported
- protected[akka] def mailbox: Deque[MessageInvocation] = unsupported
- protected[akka] def restart(reason: Throwable): Unit = unsupported
+ protected[akka] def mailbox: AnyRef = unsupported
+ protected[akka] def mailbox_=(value: AnyRef):AnyRef = unsupported
protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit = unsupported
- protected[akka] def restartLinkedActors(reason: Throwable): Unit = unsupported
+ protected[akka] def restart(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit = unsupported
+ protected[akka] def restartLinkedActors(reason: Throwable, maxNrOfRetries: Int, withinTimeRange: Int): Unit = unsupported
protected[akka] def linkedActors: JMap[String, ActorRef] = unsupported
protected[akka] def linkedActorsAsList: List[ActorRef] = unsupported
protected[akka] def invoke(messageHandle: MessageInvocation): Unit = unsupported
diff --git a/akka-core/src/main/scala/actor/ActorRegistry.scala b/akka-core/src/main/scala/actor/ActorRegistry.scala
index c568c8de03..aea37432b7 100644
--- a/akka-core/src/main/scala/actor/ActorRegistry.scala
+++ b/akka-core/src/main/scala/actor/ActorRegistry.scala
@@ -29,11 +29,6 @@ case class ActorUnregistered(actor: ActorRef) extends ActorRegistryEvent
* @author Jonas Bonér
*/
object ActorRegistry extends ListenerManagement {
-
- private val refComparator = new java.util.Comparator[ActorRef]{
- def compare(a: ActorRef,b: ActorRef) = a.uuid.compareTo(b.uuid)
- }
-
private val actorsByUUID = new ConcurrentHashMap[String, ActorRef]
private val actorsById = new ConcurrentHashMap[String, JSet[ActorRef]]
private val actorsByClassName = new ConcurrentHashMap[String, JSet[ActorRef]]
@@ -122,16 +117,16 @@ object ActorRegistry extends ListenerManagement {
if (id eq null) throw new IllegalActorStateException("Actor.id is null " + actor)
if (actorsById.containsKey(id)) actorsById.get(id).add(actor)
else {
- val set = new ConcurrentSkipListSet[ActorRef](refComparator)
+ val set = new ConcurrentSkipListSet[ActorRef]
set.add(actor)
actorsById.put(id, set)
}
// Class name
- val className = actor.actor.getClass.getName
+ val className = actor.actorClassName
if (actorsByClassName.containsKey(className)) actorsByClassName.get(className).add(actor)
else {
- val set = new ConcurrentSkipListSet[ActorRef](refComparator)
+ val set = new ConcurrentSkipListSet[ActorRef]
set.add(actor)
actorsByClassName.put(className, set)
}
@@ -149,7 +144,7 @@ object ActorRegistry extends ListenerManagement {
val id = actor.id
if (actorsById.containsKey(id)) actorsById.get(id).remove(actor)
- val className = actor.getClass.getName
+ val className = actor.actorClassName
if (actorsByClassName.containsKey(className)) actorsByClassName.get(className).remove(actor)
// notify listeners
@@ -159,7 +154,7 @@ object ActorRegistry extends ListenerManagement {
/**
* Shuts down and unregisters all actors in the system.
*/
- def shutdownAll = {
+ def shutdownAll() {
log.info("Shutting down all actors in the system...")
foreach(_.stop)
actorsByUUID.clear
diff --git a/akka-core/src/main/scala/actor/Scheduler.scala b/akka-core/src/main/scala/actor/Scheduler.scala
index 6a7187afdc..6f4f099bb2 100644
--- a/akka-core/src/main/scala/actor/Scheduler.scala
+++ b/akka-core/src/main/scala/actor/Scheduler.scala
@@ -20,7 +20,7 @@ import java.util.concurrent._
import se.scalablesolutions.akka.util.Logging
-object Scheduler {
+object Scheduler extends Logging {
import Actor._
case object UnSchedule
@@ -28,8 +28,12 @@ object Scheduler {
private var service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
private val schedulers = new ConcurrentHashMap[ActorRef, ActorRef]
+ log.info("Starting up Scheduler")
def schedule(receiver: ActorRef, message: AnyRef, initialDelay: Long, delay: Long, timeUnit: TimeUnit): ActorRef = {
+ log.trace(
+ "Schedule scheduled event\n\tevent = [%s]\n\treceiver = [%s]\n\tinitialDelay = [%s]\n\tdelay = [%s]\n\ttimeUnit = [%s]",
+ message, receiver, initialDelay, delay, timeUnit)
try {
val future = service.scheduleAtFixedRate(
new Runnable { def run = receiver ! message },
@@ -44,6 +48,9 @@ object Scheduler {
}
def scheduleOnce(receiver: ActorRef, message: AnyRef, delay: Long, timeUnit: TimeUnit): ActorRef = {
+ log.trace(
+ "Schedule one-time event\n\tevent = [%s]\n\treceiver = [%s]\n\tdelay = [%s]\n\ttimeUnit = [%s]",
+ message, receiver, delay, timeUnit)
try {
val future = service.schedule(
new Runnable { def run = receiver ! message }, delay, timeUnit).asInstanceOf[ScheduledFuture[AnyRef]]
@@ -65,6 +72,7 @@ object Scheduler {
}
def shutdown = {
+ log.info("Shutting down Scheduler")
import scala.collection.JavaConversions._
schedulers.values.foreach(_ ! UnSchedule)
schedulers.clear
@@ -72,14 +80,16 @@ object Scheduler {
}
def restart = {
+ log.info("Restarting Scheduler")
shutdown
service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
}
}
-private class ScheduleActor(future: ScheduledFuture[AnyRef]) extends Actor with Logging {
+private class ScheduleActor(future: ScheduledFuture[AnyRef]) extends Actor {
def receive = {
case Scheduler.UnSchedule =>
+ Scheduler.log.trace("Unschedule event handled by scheduleActor\n\tactorRef = [%s]", self.toString)
future.cancel(true)
self.stop
}
@@ -91,7 +101,7 @@ private object SchedulerThreadFactory extends ThreadFactory {
def newThread(r: Runnable): Thread = {
val thread = threadFactory.newThread(r)
- thread.setName("Scheduler-" + count)
+ thread.setName("akka:scheduler-" + count)
thread.setDaemon(true)
thread
}
diff --git a/akka-core/src/main/scala/actor/SerializationProtocol.scala b/akka-core/src/main/scala/actor/SerializationProtocol.scala
index d549bb8c80..20e9842cba 100644
--- a/akka-core/src/main/scala/actor/SerializationProtocol.scala
+++ b/akka-core/src/main/scala/actor/SerializationProtocol.scala
@@ -77,42 +77,38 @@ object ActorSerialization {
toSerializedActorRefProtocol(a, format).toByteArray
}
- private def toSerializedActorRefProtocol[T <: Actor](a: ActorRef, format: Format[T]): SerializedActorRefProtocol = {
+ private def toSerializedActorRefProtocol[T <: Actor](actorRef: ActorRef, format: Format[T]): SerializedActorRefProtocol = {
val lifeCycleProtocol: Option[LifeCycleProtocol] = {
def setScope(builder: LifeCycleProtocol.Builder, scope: Scope) = scope match {
case Permanent => builder.setLifeCycle(LifeCycleType.PERMANENT)
case Temporary => builder.setLifeCycle(LifeCycleType.TEMPORARY)
}
val builder = LifeCycleProtocol.newBuilder
- a.lifeCycle match {
- case Some(LifeCycle(scope, None, _)) =>
+ actorRef.lifeCycle match {
+ case Some(LifeCycle(scope)) =>
setScope(builder, scope)
Some(builder.build)
- case Some(LifeCycle(scope, Some(callbacks), _)) =>
- setScope(builder, scope)
- builder.setPreRestart(callbacks.preRestart)
- builder.setPostRestart(callbacks.postRestart)
- Some(builder.build)
case None => None
}
}
val originalAddress = AddressProtocol.newBuilder
- .setHostname(a.homeAddress.getHostName)
- .setPort(a.homeAddress.getPort)
+ .setHostname(actorRef.homeAddress.getHostName)
+ .setPort(actorRef.homeAddress.getPort)
.build
val builder = SerializedActorRefProtocol.newBuilder
- .setUuid(a.uuid)
- .setId(a.id)
- .setActorClassname(a.actorClass.getName)
+ .setUuid(actorRef.uuid)
+ .setId(actorRef.id)
+ .setActorClassname(actorRef.actorClass.getName)
.setOriginalAddress(originalAddress)
- .setIsTransactor(a.isTransactor)
- .setTimeout(a.timeout)
+ .setIsTransactor(actorRef.isTransactor)
+ .setTimeout(actorRef.timeout)
- builder.setActorInstance(ByteString.copyFrom(format.toBinary(a.actor.asInstanceOf[T])))
+ actorRef.receiveTimeout.foreach(builder.setReceiveTimeout(_))
+ builder.setActorInstance(ByteString.copyFrom(format.toBinary(actorRef.actor.asInstanceOf[T])))
lifeCycleProtocol.foreach(builder.setLifeCycle(_))
- a.supervisor.foreach(s => builder.setSupervisor(RemoteActorSerialization.toRemoteActorRefProtocol(s)))
+ actorRef.supervisor.foreach(s => builder.setSupervisor(RemoteActorSerialization.toRemoteActorRefProtocol(s)))
// FIXME: how to serialize the hotswap PartialFunction ??
//hotswap.foreach(builder.setHotswapStack(_))
builder.build
@@ -121,7 +117,8 @@ object ActorSerialization {
private def fromBinaryToLocalActorRef[T <: Actor](bytes: Array[Byte], format: Format[T]): ActorRef =
fromProtobufToLocalActorRef(SerializedActorRefProtocol.newBuilder.mergeFrom(bytes).build, format, None)
- private def fromProtobufToLocalActorRef[T <: Actor](protocol: SerializedActorRefProtocol, format: Format[T], loader: Option[ClassLoader]): ActorRef = {
+ private def fromProtobufToLocalActorRef[T <: Actor](
+ protocol: SerializedActorRefProtocol, format: Format[T], loader: Option[ClassLoader]): ActorRef = {
Actor.log.debug("Deserializing SerializedActorRefProtocol to LocalActorRef:\n" + protocol)
val serializer =
@@ -132,12 +129,8 @@ object ActorSerialization {
val lifeCycle =
if (protocol.hasLifeCycle) {
val lifeCycleProtocol = protocol.getLifeCycle
- val restartCallbacks =
- if (lifeCycleProtocol.hasPreRestart || lifeCycleProtocol.hasPostRestart)
- Some(RestartCallbacks(lifeCycleProtocol.getPreRestart, lifeCycleProtocol.getPostRestart))
- else None
- Some(if (lifeCycleProtocol.getLifeCycle == LifeCycleType.PERMANENT) LifeCycle(Permanent, restartCallbacks)
- else if (lifeCycleProtocol.getLifeCycle == LifeCycleType.TEMPORARY) LifeCycle(Temporary, restartCallbacks)
+ Some(if (lifeCycleProtocol.getLifeCycle == LifeCycleType.PERMANENT) LifeCycle(Permanent)
+ else if (lifeCycleProtocol.getLifeCycle == LifeCycleType.TEMPORARY) LifeCycle(Temporary)
else throw new IllegalActorStateException("LifeCycle type is not valid: " + lifeCycleProtocol.getLifeCycle))
} else None
@@ -161,6 +154,7 @@ object ActorSerialization {
protocol.getOriginalAddress.getPort,
if (protocol.hasIsTransactor) protocol.getIsTransactor else false,
if (protocol.hasTimeout) protocol.getTimeout else Actor.TIMEOUT,
+ if (protocol.hasReceiveTimeout) Some(protocol.getReceiveTimeout) else None,
lifeCycle,
supervisor,
hotswap,
@@ -223,26 +217,30 @@ object RemoteActorSerialization {
.build
}
- def createRemoteRequestProtocolBuilder(ar: ActorRef,
- message: Any, isOneWay: Boolean, senderOption: Option[ActorRef]): RemoteRequestProtocol.Builder = {
- import ar._
- val protocol = RemoteRequestProtocol.newBuilder
- .setId(RemoteRequestProtocolIdFactory.nextId)
- .setMessage(MessageSerializer.serialize(message))
+ def createRemoteRequestProtocolBuilder(actorRef: ActorRef, message: Any, isOneWay: Boolean, senderOption: Option[ActorRef]):
+ RemoteRequestProtocol.Builder = {
+ import actorRef._
+
+ val actorInfo = ActorInfoProtocol.newBuilder
+ .setUuid(uuid)
.setTarget(actorClassName)
.setTimeout(timeout)
- .setUuid(uuid)
- .setIsActor(true)
+ .setActorType(ActorType.SCALA_ACTOR)
+ .build
+
+ val request = RemoteRequestProtocol.newBuilder
+ .setId(RemoteRequestProtocolIdFactory.nextId)
+ .setMessage(MessageSerializer.serialize(message))
+ .setActorInfo(actorInfo)
.setIsOneWay(isOneWay)
- .setIsEscaped(false)
val id = registerSupervisorAsRemoteActor
- if (id.isDefined) protocol.setSupervisorUuid(id.get)
+ if (id.isDefined) request.setSupervisorUuid(id.get)
senderOption.foreach { sender =>
RemoteServer.getOrCreateServer(sender.homeAddress).register(sender.uuid, sender)
- protocol.setSender(toRemoteActorRefProtocol(sender))
+ request.setSender(toRemoteActorRefProtocol(sender))
}
- protocol
+ request
}
}
diff --git a/akka-core/src/main/scala/actor/Supervisor.scala b/akka-core/src/main/scala/actor/Supervisor.scala
index ecbbf9bb9d..9b56bddf38 100644
--- a/akka-core/src/main/scala/actor/Supervisor.scala
+++ b/akka-core/src/main/scala/actor/Supervisor.scala
@@ -161,8 +161,8 @@ sealed class Supervisor private[akka] (
_childActors.put(className, actorRef :: currentActors)
actorRef.lifeCycle = Some(lifeCycle)
supervisor.link(actorRef)
- remoteAddress.foreach(address =>
- RemoteServer.registerActor(new InetSocketAddress(address.hostname, address.port), actorRef.uuid, actorRef))
+ remoteAddress.foreach(address => RemoteServer.registerActor(
+ new InetSocketAddress(address.hostname, address.port), actorRef.uuid, actorRef))
case supervisorConfig @ SupervisorConfig(_, _) => // recursive supervisor configuration
val childSupervisor = Supervisor(supervisorConfig)
supervisor.link(childSupervisor.supervisor)
@@ -180,14 +180,23 @@ final class SupervisorActor private[akka] (
handler: FaultHandlingStrategy,
trapExceptions: List[Class[_ <: Throwable]]) extends Actor {
import self._
+
trapExit = trapExceptions
faultHandler = Some(handler)
override def shutdown(): Unit = shutdownLinkedActors
def receive = {
+ // FIXME add a way to respond to MaximumNumberOfRestartsWithinTimeRangeReached in declaratively configured Supervisor
+ case MaximumNumberOfRestartsWithinTimeRangeReached(
+ victim, maxNrOfRetries, withinTimeRange, lastExceptionCausingRestart) =>
+ Actor.log.warning(
+ "Declaratively configured supervisor received a [MaximumNumberOfRestartsWithinTimeRangeReached] notification," +
+ "\n\tbut there is currently no way of handling it in a declaratively configured supervisor." +
+ "\n\tIf you want to be able to handle this error condition then you need to create the supervision tree programatically." +
+ "\n\tThis will be supported in the future.")
case unknown => throw new SupervisorException(
- "SupervisorActor can not respond to messages. Unknown message [" + unknown + "]")
+ "SupervisorActor can not respond to messages.\n\tUnknown message [" + unknown + "]")
}
}
diff --git a/akka-core/src/main/scala/actor/TypedActor.scala b/akka-core/src/main/scala/actor/TypedActor.scala
new file mode 100644
index 0000000000..ae72da4d70
--- /dev/null
+++ b/akka-core/src/main/scala/actor/TypedActor.scala
@@ -0,0 +1,804 @@
+/**
+ * Copyright (C) 2009-2010 Scalable Solutions AB
+ */
+
+package se.scalablesolutions.akka.actor
+
+import Actor._
+import se.scalablesolutions.akka.config.FaultHandlingStrategy
+import se.scalablesolutions.akka.remote.protocol.RemoteProtocol._
+import se.scalablesolutions.akka.remote.{MessageSerializer, RemoteClient, RemoteRequestProtocolIdFactory}
+import se.scalablesolutions.akka.dispatch.{MessageDispatcher, Future, CompletableFuture}
+import se.scalablesolutions.akka.config.ScalaConfig._
+import se.scalablesolutions.akka.serialization.Serializer
+import se.scalablesolutions.akka.util._
+
+import org.codehaus.aspectwerkz.joinpoint.{MethodRtti, JoinPoint}
+import org.codehaus.aspectwerkz.proxy.Proxy
+import org.codehaus.aspectwerkz.annotation.{Aspect, Around}
+
+import java.net.InetSocketAddress
+import java.lang.reflect.{InvocationTargetException, Method, Field}
+
+import scala.reflect.BeanProperty
+
+/**
+ * FIXME: document TypedActor
+ *
+ * Here is an example of usage (in Java):
+ *
+ * class PingImpl extends TypedActor implements Ping {
+ * public void hit(int count) {
+ * Pong pong = (Pong) getContext().getSender();
+ * pong.hit(count++);
+ * }
+ *
+ * @Override
+ * public void init() {
+ * ... // optional initialization on start
+ * }
+ *
+ * @Override
+ * public void shutdown() {
+ * ... // optional cleanup on stop
+ * }
+ *
+ * ... // more life-cycle callbacks if needed
+ * }
+ *
+ * // create the ping actor
+ * Ping ping = TypedActor.newInstance(Ping.class, PingImpl.class);
+ *
+ * ping.hit(1); // use the actor
+ * ping.hit(1);
+ *
+ * // stop the actor
+ * TypedActor.stop(ping);
+ *
+ *
+ * Here is an example of usage (in Scala):
+ *
+ * class PingImpl extends TypedActor with Ping {
+ * def hit(count: Int) = {
+ * val pong = context.sender.asInstanceOf[Pong]
+ * pong.hit(count += 1)
+ * }
+ *
+ * override def init = {
+ * ... // optional initialization on start
+ * }
+ *
+ * override def shutdown = {
+ * ... // optional cleanup on stop
+ * }
+ *
+ * ... // more life-cycle callbacks if needed
+ * }
+ *
+ * // create the ping actor
+ * val ping = TypedActor.newInstance(classOf[Ping], classOf[PingImpl])
+ *
+ * ping.hit(1) // use the actor
+ * ping.hit(1)
+ *
+ * // stop the actor
+ * TypedActor.stop(ping)
+ *
+ *
+ * @author Jonas Bonér
+ */
+abstract class TypedActor extends Logging {
+
+ /**
+ * Holds RTTI (runtime type information) for the TypedActor, f.e. current 'sender'
+ * reference, the 'senderFuture' reference etc.
+ *
+ * This class does not contain static information but is updated by the runtime system
+ * at runtime.
+ *
+ * You can get a hold of the context using either the 'getContext()' or 'context'
+ * methods from the 'TypedActor' base class.
+ *
+ *
+ * Here is an example of usage (in Java):
+ *
+ */
+ @BeanProperty protected var context: TypedActorContext = _
+
+ /**
+ * The uuid for the Typed Actor.
+ */
+ @BeanProperty @volatile var uuid = UUID.newUuid.toString
+
+ /**
+ * Identifier for actor, does not have to be a unique one. Default is the 'uuid'.
+ *
+ * This field is used for logging, AspectRegistry.actorsFor(id), identifier for remote
+ * actor in RemoteServer etc.But also as the identifier for persistence, which means
+ * that you can use a custom name to be able to retrieve the "correct" persisted state
+ * upon restart, remote restart etc.
+ *
+ * This property can be set to a custom ID.
+ */
+ @BeanProperty @volatile protected var id: String = uuid
+
+ /**
+ * Defines the default timeout for '!!' and '!!!' invocations,
+ * e.g. the timeout for the future returned by the call to '!!' and '!!!'.
+ *
+ * This property can be set to a custom timeout.
+ */
+ @BeanProperty @volatile protected var timeout: Long = Actor.TIMEOUT
+
+ /**
+ * User overridable callback.
+ *
+ * Is called when an Actor is started by invoking 'actor.start'.
+ */
+ def init {}
+
+ /**
+ * User overridable callback.
+ *
+ * Is called when 'actor.stop' is invoked.
+ */
+ def shutdown {}
+
+ /**
+ * User overridable callback.
+ *
+ * Is called on a crashed Actor right BEFORE it is restarted to allow clean up of resources before Actor is terminated.
+ */
+ def preRestart(reason: Throwable) {}
+
+ /**
+ * User overridable callback.
+ *
+ * Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash.
+ */
+ def postRestart(reason: Throwable) {}
+
+ /**
+ * User overridable callback.
+ *
+ * Is called during initialization. Can be used to initialize transactional state. Will be invoked within a transaction.
+ */
+ def initTransactionalState {}
+}
+
+/**
+ * FIXME: document TypedTransactor
+ *
+ * @author Jonas Bonér
+ */
+abstract class TypedTransactor extends TypedActor
+
+/**
+ * Configuration factory for TypedActors.
+ *
+ * FIXDOC: document TypedActorConfiguration
+ *
+ * @author Jonas Bonér
+ */
+final class TypedActorConfiguration {
+ private[akka] var _timeout: Long = Actor.TIMEOUT
+ private[akka] var _transactionRequired = false
+ private[akka] var _host: Option[InetSocketAddress] = None
+ private[akka] var _messageDispatcher: Option[MessageDispatcher] = None
+
+ def timeout = _timeout
+ def timeout(timeout: Duration) : TypedActorConfiguration = {
+ _timeout = timeout.toMillis
+ this
+ }
+
+ def makeTransactionRequired() : TypedActorConfiguration = {
+ _transactionRequired = true;
+ this
+ }
+
+ def makeRemote(hostname: String, port: Int) : TypedActorConfiguration = {
+ _host = Some(new InetSocketAddress(hostname, port))
+ this
+ }
+
+ def dispatcher(messageDispatcher: MessageDispatcher) : TypedActorConfiguration = {
+ _messageDispatcher = Some(messageDispatcher)
+ this
+ }
+}
+
+/**
+ * Holds RTTI (runtime type information) for the TypedActor, f.e. current 'sender'
+ * reference, the 'senderFuture' reference etc.
+ *
+ * This class does not contain static information but is updated by the runtime system
+ * at runtime.
+ *
+ * You can get a hold of the context using either the 'getContext()' or 'context'
+ * methods from the 'TypedActor' base class.
+ *
+ * Here is an example of usage (from Java):
+ *
+ *
+ * @author Jonas Bonér
+ */
+final class TypedActorContext {
+ private[akka] var _self: AnyRef = _
+ private[akka] var _sender: AnyRef = _
+ private[akka] var _senderFuture: CompletableFuture[Any] = _
+
+ /**
+ * Returns the current sender reference.
+ * Scala style getter.
+ */
+ def sender: AnyRef = {
+ if (_sender eq null) throw new IllegalActorStateException("Sender reference should not be null.")
+ else _sender
+ }
+
+ /**
+ * Returns the current sender reference.
+ * Java style getter.
+ */
+ def getSender: AnyRef = {
+ if (_sender eq null) throw new IllegalActorStateException("Sender reference should not be null.")
+ else _sender
+ }
+
+ /**
+ * Returns the current sender future TypedActor reference.
+ * Scala style getter.
+ */
+ def senderFuture: Option[CompletableFuture[Any]] = if (_senderFuture eq null) None else Some(_senderFuture)
+
+ /**
+ * Returns the current sender future TypedActor reference.
+ * Java style getter.
+ * This method returns 'null' if the sender future is not available.
+ */
+ def getSenderFuture = _senderFuture
+}
+
+/**
+ * Factory class for creating TypedActors out of plain POJOs and/or POJOs with interfaces.
+ *
+ * @author Jonas Bonér
+ */
+object TypedActor extends Logging {
+ import Actor.actorOf
+
+ val AKKA_CAMEL_ROUTING_SCHEME = "akka".intern
+ private[actor] val AW_PROXY_PREFIX = "$$ProxiedByAW".intern
+
+ def newInstance[T](intfClass: Class[T], targetClass: Class[_], timeout: Long): T = {
+ newInstance(intfClass, newTypedActor(targetClass), actorOf(new Dispatcher(false)), None, timeout)
+ }
+
+ def newInstance[T](intfClass: Class[T], targetClass: Class[_]): T = {
+ newInstance(intfClass, newTypedActor(targetClass), actorOf(new Dispatcher(false)), None, Actor.TIMEOUT)
+ }
+
+ def newRemoteInstance[T](intfClass: Class[T], targetClass: Class[_], timeout: Long, hostname: String, port: Int): T = {
+ newInstance(intfClass, newTypedActor(targetClass), actorOf(new Dispatcher(false)), Some(new InetSocketAddress(hostname, port)), timeout)
+ }
+
+ def newRemoteInstance[T](intfClass: Class[T], targetClass: Class[_], hostname: String, port: Int): T = {
+ newInstance(intfClass, newTypedActor(targetClass), actorOf(new Dispatcher(false)), Some(new InetSocketAddress(hostname, port)), Actor.TIMEOUT)
+ }
+
+ def newInstance[T](intfClass: Class[T], targetClass: Class[_], config: TypedActorConfiguration): T = {
+ val actor = actorOf(new Dispatcher(config._transactionRequired))
+ if (config._messageDispatcher.isDefined) actor.dispatcher = config._messageDispatcher.get
+ newInstance(intfClass, newTypedActor(targetClass), actor, config._host, config.timeout)
+ }
+
+ private[akka] def newInstance[T](intfClass: Class[T], targetInstance: TypedActor, actorRef: ActorRef,
+ remoteAddress: Option[InetSocketAddress], timeout: Long): T = {
+ val context = injectTypedActorContext(targetInstance)
+ val proxy = Proxy.newInstance(Array(intfClass), Array(targetInstance), true, false)
+ actorRef.actor.asInstanceOf[Dispatcher].initialize(targetInstance.getClass, targetInstance, proxy, context)
+ actorRef.timeout = timeout
+ if (remoteAddress.isDefined) actorRef.makeRemote(remoteAddress.get)
+ AspectInitRegistry.register(proxy, AspectInit(intfClass, targetInstance, actorRef, remoteAddress, timeout))
+ actorRef.start
+ proxy.asInstanceOf[T]
+ }
+
+ // NOTE: currently not used - but keep it around
+ private[akka] def newInstance[T <: TypedActor](
+ targetClass: Class[T], actorRef: ActorRef, remoteAddress: Option[InetSocketAddress], timeout: Long): T = {
+ val proxy = {
+ val instance = Proxy.newInstance(targetClass, true, false)
+ if (instance.isInstanceOf[TypedActor]) instance.asInstanceOf[TypedActor]
+ else throw new IllegalActorStateException("Actor [" + targetClass.getName + "] is not a sub class of 'TypedActor'")
+ }
+ val context = injectTypedActorContext(proxy)
+ actorRef.actor.asInstanceOf[Dispatcher].initialize(targetClass, proxy, proxy, context)
+ actorRef.timeout = timeout
+ if (remoteAddress.isDefined) actorRef.makeRemote(remoteAddress.get)
+ AspectInitRegistry.register(proxy, AspectInit(targetClass, proxy, actorRef, remoteAddress, timeout))
+ actorRef.start
+ proxy.asInstanceOf[T]
+ }
+
+ /**
+ * Stops the current Typed Actor.
+ */
+ def stop(proxy: AnyRef): Unit = AspectInitRegistry.initFor(proxy).actorRef.stop
+
+ /**
+ * Get the underlying dispatcher actor for the given Typed Actor.
+ */
+ def actorFor(proxy: AnyRef): Option[ActorRef] =
+ ActorRegistry
+ .actorsFor(classOf[Dispatcher])
+ .find(a => a.actor.asInstanceOf[Dispatcher].proxy == proxy)
+
+ /**
+ * Links an other Typed Actor to this Typed Actor.
+ * @param supervisor the supervisor Typed Actor
+ * @param supervised the Typed Actor to link
+ */
+ def link(supervisor: AnyRef, supervised: AnyRef) = {
+ val supervisorActor = actorFor(supervisor).getOrElse(
+ throw new IllegalActorStateException("Can't link when the supervisor is not an Typed Actor"))
+ val supervisedActor = actorFor(supervised).getOrElse(
+ throw new IllegalActorStateException("Can't link when the supervised is not an Typed Actor"))
+ supervisorActor.link(supervisedActor)
+ }
+
+ /**
+ * Links an other Typed Actor to this Typed Actor and sets the fault handling for the supervisor.
+ * @param supervisor the supervisor Typed Actor
+ * @param supervised the Typed Actor to link
+ * @param handler fault handling strategy
+ * @param trapExceptions array of exceptions that should be handled by the supervisor
+ */
+ def link(supervisor: AnyRef, supervised: AnyRef,
+ handler: FaultHandlingStrategy, trapExceptions: Array[Class[_ <: Throwable]]) = {
+ val supervisorActor = actorFor(supervisor).getOrElse(
+ throw new IllegalActorStateException("Can't link when the supervisor is not an Typed Actor"))
+ val supervisedActor = actorFor(supervised).getOrElse(
+ throw new IllegalActorStateException("Can't link when the supervised is not an Typed Actor"))
+ supervisorActor.trapExit = trapExceptions.toList
+ supervisorActor.faultHandler = Some(handler)
+ supervisorActor.link(supervisedActor)
+ }
+
+ /**
+ * Unlink the supervised Typed Actor from the supervisor.
+ * @param supervisor the supervisor Typed Actor
+ * @param supervised the Typed Actor to unlink
+ */
+ def unlink(supervisor: AnyRef, supervised: AnyRef) = {
+ val supervisorActor = actorFor(supervisor).getOrElse(
+ throw new IllegalActorStateException("Can't unlink when the supervisor is not an Typed Actor"))
+ val supervisedActor = actorFor(supervised).getOrElse(
+ throw new IllegalActorStateException("Can't unlink when the supervised is not an Typed Actor"))
+ supervisorActor.unlink(supervisedActor)
+ }
+
+ /**
+ * Sets the trap exit for the given supervisor Typed Actor.
+ * @param supervisor the supervisor Typed Actor
+ * @param trapExceptions array of exceptions that should be handled by the supervisor
+ */
+ def trapExit(supervisor: AnyRef, trapExceptions: Array[Class[_ <: Throwable]]) = {
+ val supervisorActor = actorFor(supervisor).getOrElse(
+ throw new IllegalActorStateException("Can't set trap exceptions when the supervisor is not an Typed Actor"))
+ supervisorActor.trapExit = trapExceptions.toList
+ this
+ }
+
+ /**
+ * Sets the fault handling strategy for the given supervisor Typed Actor.
+ * @param supervisor the supervisor Typed Actor
+ * @param handler fault handling strategy
+ */
+ def faultHandler(supervisor: AnyRef, handler: FaultHandlingStrategy) = {
+ val supervisorActor = actorFor(supervisor).getOrElse(
+ throw new IllegalActorStateException("Can't set fault handler when the supervisor is not an Typed Actor"))
+ supervisorActor.faultHandler = Some(handler)
+ this
+ }
+
+ private def injectTypedActorContext(typedActor: AnyRef): Option[TypedActorContext] = {
+ def injectTypedActorContext0(typedActor: AnyRef, clazz: Class[_]): Option[TypedActorContext] = {
+ val contextField = clazz.getDeclaredFields.toList.find(_.getType == classOf[TypedActorContext])
+ if (contextField.isDefined) {
+ contextField.get.setAccessible(true)
+ val context = new TypedActorContext
+ contextField.get.set(typedActor, context)
+ Some(context)
+ } else {
+ val parent = clazz.getSuperclass
+ if (parent != null) injectTypedActorContext0(typedActor, parent)
+ else {
+ log.ifTrace("Can't set 'TypedActorContext' for TypedActor [" +
+ typedActor.getClass.getName +
+ "] since no field of this type could be found.")
+ None
+ }
+ }
+ }
+ injectTypedActorContext0(typedActor, typedActor.getClass)
+ }
+
+ private[akka] def newTypedActor(targetClass: Class[_]): TypedActor = {
+ val instance = targetClass.newInstance
+ val typedActor =
+ if (instance.isInstanceOf[TypedActor]) instance.asInstanceOf[TypedActor]
+ else throw new IllegalArgumentException("Actor [" + targetClass.getName + "] is not a sub class of 'TypedActor'")
+ typedActor.init
+ import se.scalablesolutions.akka.stm.local.atomic
+ atomic {
+ typedActor.initTransactionalState
+ }
+ typedActor
+ }
+
+ private[akka] def supervise(restartStrategy: RestartStrategy, components: List[Supervise]): Supervisor =
+ Supervisor(SupervisorConfig(restartStrategy, components))
+}
+
+/**
+ * Internal helper class to help pass the contextual information between threads.
+ *
+ * @author Jonas Bonér
+ */
+private[akka] object TypedActorContext {
+ import scala.util.DynamicVariable
+ private[actor] val sender = new DynamicVariable[AnyRef](null)
+ private[actor] val senderFuture = new DynamicVariable[CompletableFuture[Any]](null)
+}
+
+/**
+ * @author Jonas Bonér
+ */
+private[akka] object AspectInitRegistry extends ListenerManagement {
+ private val initializations = new java.util.concurrent.ConcurrentHashMap[AnyRef, AspectInit]
+
+ def initFor(proxy: AnyRef) = initializations.get(proxy)
+
+ def register(proxy: AnyRef, init: AspectInit) = {
+ val res = initializations.put(proxy, init)
+ foreachListener(_ ! AspectInitRegistered(proxy, init))
+ res
+ }
+
+ def unregister(proxy: AnyRef) = {
+ val res = initializations.remove(proxy)
+ foreachListener(_ ! AspectInitUnregistered(proxy, res))
+ res
+ }
+}
+
+private[akka] sealed trait AspectInitRegistryEvent
+private[akka] case class AspectInitRegistered(proxy: AnyRef, init: AspectInit) extends AspectInitRegistryEvent
+private[akka] case class AspectInitUnregistered(proxy: AnyRef, init: AspectInit) extends AspectInitRegistryEvent
+
+/**
+ * @author Jonas Bonér
+ */
+private[akka] sealed case class AspectInit(
+ val interfaceClass: Class[_],
+ val targetInstance: TypedActor,
+ val actorRef: ActorRef,
+ val remoteAddress: Option[InetSocketAddress],
+ val timeout: Long) {
+ def this(interfaceClass: Class[_], targetInstance: TypedActor, actorRef: ActorRef, timeout: Long) =
+ this(interfaceClass, targetInstance, actorRef, None, timeout)
+}
+
+/**
+ * AspectWerkz Aspect that is turning POJO into TypedActor.
+ *
+ * Is deployed on a 'perInstance' basis with the pointcut 'execution(* *.*(..))',
+ * e.g. all methods on the instance.
+ *
+ * @author Jonas Bonér
+ */
+@Aspect("perInstance")
+private[akka] sealed class TypedActorAspect {
+ @volatile private var isInitialized = false
+ @volatile private var isStopped = false
+ private var interfaceClass: Class[_] = _
+ private var targetInstance: TypedActor = _
+ private var actorRef: ActorRef = _
+ private var remoteAddress: Option[InetSocketAddress] = _
+ private var timeout: Long = _
+ private var uuid: String = _
+ @volatile private var instance: TypedActor = _
+
+ @Around("execution(* *.*(..))")
+ def invoke(joinPoint: JoinPoint): AnyRef = {
+ if (!isInitialized) {
+ val init = AspectInitRegistry.initFor(joinPoint.getThis)
+ interfaceClass = init.interfaceClass
+ targetInstance = init.targetInstance
+ uuid = targetInstance.uuid
+ actorRef = init.actorRef
+ remoteAddress = init.remoteAddress
+ timeout = init.timeout
+ isInitialized = true
+ }
+ dispatch(joinPoint)
+ }
+
+ private def dispatch(joinPoint: JoinPoint) = {
+ if (remoteAddress.isDefined) remoteDispatch(joinPoint)
+ else localDispatch(joinPoint)
+ }
+
+ private def localDispatch(joinPoint: JoinPoint): AnyRef = {
+ val rtti = joinPoint.getRtti.asInstanceOf[MethodRtti]
+ val isOneWay = isVoid(rtti)
+ val sender = TypedActorContext.sender.value
+ val senderFuture = TypedActorContext.senderFuture.value
+
+ if (!actorRef.isRunning && !isStopped) {
+ isStopped = true
+ joinPoint.proceed
+
+ } else if (isOneWay) {
+ actorRef ! Invocation(joinPoint, true, true, sender, senderFuture)
+ null.asInstanceOf[AnyRef]
+
+ } else {
+ val result = (actorRef !! (Invocation(joinPoint, false, isOneWay, sender, senderFuture), timeout)).as[AnyRef]
+ if (result.isDefined) result.get
+ else throw new IllegalActorStateException("No result defined for invocation [" + joinPoint + "]")
+ }
+ }
+
+ private def remoteDispatch(joinPoint: JoinPoint): AnyRef = {
+ val rtti = joinPoint.getRtti.asInstanceOf[MethodRtti]
+ val isOneWay = isVoid(rtti)
+ val (message: Array[AnyRef], isEscaped) = escapeArguments(rtti.getParameterValues)
+
+ val typedActorInfo = TypedActorInfoProtocol.newBuilder
+ .setInterface(interfaceClass.getName)
+ .setMethod(rtti.getMethod.getName)
+ .build
+
+ val actorInfo = ActorInfoProtocol.newBuilder
+ .setUuid(uuid)
+ .setTarget(targetInstance.getClass.getName)
+ .setTimeout(timeout)
+ .setActorType(ActorType.TYPED_ACTOR)
+ .setTypedActorInfo(typedActorInfo)
+ .build
+
+ val requestBuilder = RemoteRequestProtocol.newBuilder
+ .setId(RemoteRequestProtocolIdFactory.nextId)
+ .setMessage(MessageSerializer.serialize(message))
+ .setActorInfo(actorInfo)
+ .setIsOneWay(isOneWay)
+
+ val id = actorRef.registerSupervisorAsRemoteActor
+ if (id.isDefined) requestBuilder.setSupervisorUuid(id.get)
+
+ val remoteMessage = requestBuilder.build
+
+ val future = RemoteClient.clientFor(remoteAddress.get).send(remoteMessage, None)
+
+ if (isOneWay) null // for void methods
+ else {
+ if (future.isDefined) {
+ future.get.await
+ val result = getResultOrThrowException(future.get)
+ if (result.isDefined) result.get
+ else throw new IllegalActorStateException("No result returned from call to [" + joinPoint + "]")
+ } else throw new IllegalActorStateException("No future returned from call to [" + joinPoint + "]")
+ }
+ }
+
+ private def getResultOrThrowException[T](future: Future[T]): Option[T] =
+ if (future.exception.isDefined) {
+ val (_, cause) = future.exception.get
+ throw cause
+ } else future.result
+
+ private def isVoid(rtti: MethodRtti) = rtti.getMethod.getReturnType == java.lang.Void.TYPE
+
+ private def escapeArguments(args: Array[AnyRef]): Tuple2[Array[AnyRef], Boolean] = {
+ var isEscaped = false
+ val escapedArgs = for (arg <- args) yield {
+ val clazz = arg.getClass
+ if (clazz.getName.contains(TypedActor.AW_PROXY_PREFIX)) {
+ isEscaped = true
+ TypedActor.AW_PROXY_PREFIX + clazz.getSuperclass.getName
+ } else arg
+ }
+ (escapedArgs, isEscaped)
+ }
+}
+
+/**
+ * Represents a snapshot of the current invocation.
+ *
+ * @author Jonas Bonér
+ */
+@serializable private[akka] case class Invocation(
+ joinPoint: JoinPoint, isOneWay: Boolean, isVoid: Boolean, sender: AnyRef, senderFuture: CompletableFuture[Any]) {
+
+ override def toString: String = synchronized {
+ "Invocation [" +
+ "\n\t\tmethod = " + joinPoint.getRtti.asInstanceOf[MethodRtti].getMethod.getName + " @ " + joinPoint.getTarget.getClass.getName +
+ "\n\t\tisOneWay = " + isOneWay +
+ "\n\t\tisVoid = " + isVoid +
+ "\n\t\tsender = " + sender +
+ "\n\t\tsenderFuture = " + senderFuture +
+ "]"
+ }
+
+ override def hashCode: Int = synchronized {
+ var result = HashCode.SEED
+ result = HashCode.hash(result, joinPoint)
+ result = HashCode.hash(result, isOneWay)
+ result = HashCode.hash(result, isVoid)
+ result = HashCode.hash(result, sender)
+ result = HashCode.hash(result, senderFuture)
+ result
+ }
+
+ override def equals(that: Any): Boolean = synchronized {
+ that != null &&
+ that.isInstanceOf[Invocation] &&
+ that.asInstanceOf[Invocation].joinPoint == joinPoint &&
+ that.asInstanceOf[Invocation].isOneWay == isOneWay &&
+ that.asInstanceOf[Invocation].isVoid == isVoid &&
+ that.asInstanceOf[Invocation].sender == sender &&
+ that.asInstanceOf[Invocation].senderFuture == senderFuture
+ }
+}
+
+object Dispatcher {
+ val ZERO_ITEM_CLASS_ARRAY = Array[Class[_]]()
+ val ZERO_ITEM_OBJECT_ARRAY = Array[Object]()
+}
+
+/**
+ * Generic Actor managing Invocation dispatch, transaction and error management.
+ *
+ * @author Jonas Bonér
+ */
+private[akka] class Dispatcher(transactionalRequired: Boolean) extends Actor {
+ import Dispatcher._
+
+ private[actor] var proxy: AnyRef = _
+ private var context: Option[TypedActorContext] = None
+ private var targetClass: Class[_] = _
+ @volatile private[akka] var targetInstance: TypedActor = _
+ private var proxyDelegate: Field = _
+
+ private[actor] def initialize(
+ targetClass: Class[_], targetInstance: TypedActor, proxy: AnyRef, ctx: Option[TypedActorContext]) = {
+ if (transactionalRequired || isTransactional(targetClass)) self.makeTransactionRequired
+
+ self.id = targetClass.getName
+ this.targetClass = targetClass
+ this.proxy = proxy
+ this.targetInstance = targetInstance
+ this.context = ctx
+
+ proxyDelegate = {
+ val field = proxy.getClass.getDeclaredField("DELEGATE_0")
+ field.setAccessible(true)
+ field
+ }
+
+ if (self.lifeCycle.isEmpty) self.lifeCycle = Some(LifeCycle(Permanent))
+ }
+
+ def receive = {
+ case invocation @ Invocation(joinPoint, isOneWay, _, sender, senderFuture) =>
+ TypedActor.log.ifTrace("Invoking Typed Actor with message:\n" + invocation)
+ context.foreach { ctx =>
+ if (sender ne null) ctx._sender = sender
+ if (senderFuture ne null) ctx._senderFuture = senderFuture
+ }
+ TypedActorContext.sender.value = joinPoint.getThis // set next sender
+ self.senderFuture.foreach(TypedActorContext.senderFuture.value = _)
+ if (Actor.SERIALIZE_MESSAGES) serializeArguments(joinPoint)
+ if (isOneWay) joinPoint.proceed
+ else self.reply(joinPoint.proceed)
+
+ // Jan Kronquist: started work on issue 121
+ case Link(proxy) => self.link(proxy)
+ case Unlink(proxy) => self.unlink(proxy)
+ case unexpected => throw new IllegalActorStateException(
+ "Unexpected message [" + unexpected + "] sent to [" + this + "]")
+ }
+
+ override def preRestart(reason: Throwable) {
+ targetInstance.preRestart(reason)
+
+ // rewrite target instance in Dispatcher and AspectWerkz Proxy
+ targetInstance = TypedActor.newTypedActor(targetClass)
+ proxyDelegate.set(proxy, targetInstance)
+ }
+
+ override def postRestart(reason: Throwable) {
+ targetInstance.postRestart(reason)
+ }
+
+ override def shutdown {
+ targetInstance.shutdown
+ AspectInitRegistry.unregister(proxy);
+ }
+
+ override def initTransactionalState {
+ targetInstance.initTransactionalState
+ }
+
+ def isTransactional(clazz: Class[_]): Boolean =
+ if (clazz == null) false
+ else if (clazz.isAssignableFrom(classOf[TypedTransactor])) true
+ else isTransactional(clazz.getSuperclass)
+
+ private def serializeArguments(joinPoint: JoinPoint) = {
+ val args = joinPoint.getRtti.asInstanceOf[MethodRtti].getParameterValues
+ var unserializable = false
+ var hasMutableArgument = false
+ for (arg <- args.toList) {
+ if (!arg.isInstanceOf[String] &&
+ !arg.isInstanceOf[Byte] &&
+ !arg.isInstanceOf[Int] &&
+ !arg.isInstanceOf[Long] &&
+ !arg.isInstanceOf[Float] &&
+ !arg.isInstanceOf[Double] &&
+ !arg.isInstanceOf[Boolean] &&
+ !arg.isInstanceOf[Char] &&
+ !arg.isInstanceOf[java.lang.Byte] &&
+ !arg.isInstanceOf[java.lang.Integer] &&
+ !arg.isInstanceOf[java.lang.Long] &&
+ !arg.isInstanceOf[java.lang.Float] &&
+ !arg.isInstanceOf[java.lang.Double] &&
+ !arg.isInstanceOf[java.lang.Boolean] &&
+ !arg.isInstanceOf[java.lang.Character]) {
+ hasMutableArgument = true
+ }
+ if (arg.getClass.getName.contains(TypedActor.AW_PROXY_PREFIX)) unserializable = true
+ }
+ if (!unserializable && hasMutableArgument) {
+ val copyOfArgs = Serializer.Java.deepClone(args)
+ joinPoint.getRtti.asInstanceOf[MethodRtti].setParameterValues(copyOfArgs.asInstanceOf[Array[AnyRef]])
+ }
+ }
+}
diff --git a/akka-core/src/main/scala/actor/UntypedActor.scala b/akka-core/src/main/scala/actor/UntypedActor.scala
new file mode 100644
index 0000000000..8ea36531e8
--- /dev/null
+++ b/akka-core/src/main/scala/actor/UntypedActor.scala
@@ -0,0 +1,580 @@
+/**
+ * Copyright (C) 2009-2010 Scalable Solutions AB
+ */
+
+package se.scalablesolutions.akka.actor
+
+import se.scalablesolutions.akka.dispatch._
+import se.scalablesolutions.akka.stm.global._
+import se.scalablesolutions.akka.config.{AllForOneStrategy, OneForOneStrategy, FaultHandlingStrategy}
+import se.scalablesolutions.akka.config.ScalaConfig._
+
+import java.net.InetSocketAddress
+
+/**
+ * Subclass this abstract class to create a MDB-style untyped actor.
+ *
+ * This class is meant to be used from Java.
+ *
+ * Here is an example on how to create and use an UntypedActor:
+ *
+ * public class SampleUntypedActor extends UntypedActor {
+ * public void onReceive(Object message, UntypedActorRef self) throws Exception {
+ * if (message instanceof String) {
+ * String msg = (String)message;
+ *
+ * if (msg.equals("UseReply")) {
+ * // Reply to original sender of message using the 'replyUnsafe' method
+ * self.replyUnsafe(msg + ":" + self.getUuid());
+ *
+ * } else if (msg.equals("UseSender") && self.getSender().isDefined()) {
+ * // Reply to original sender of message using the sender reference
+ * // also passing along my own refererence (the self)
+ * self.getSender().get().sendOneWay(msg, self);
+ *
+ * } else if (msg.equals("UseSenderFuture") && self.getSenderFuture().isDefined()) {
+ * // Reply to original sender of message using the sender future reference
+ * self.getSenderFuture().get().completeWithResult(msg);
+ *
+ * } else if (msg.equals("SendToSelf")) {
+ * // Send message to the actor itself recursively
+ * self.sendOneWay(msg)
+ *
+ * } else if (msg.equals("ForwardMessage")) {
+ * // Retreive an actor from the ActorRegistry by ID and get an ActorRef back
+ * ActorRef actorRef = ActorRegistry.actorsFor("some-actor-id").head();
+ * // Wrap the ActorRef in an UntypedActorRef and forward the message to this actor
+ * UntypedActorRef.wrap(actorRef).forward(msg, self);
+ *
+ * } else throw new IllegalArgumentException("Unknown message: " + message);
+ * } else throw new IllegalArgumentException("Unknown message: " + message);
+ * }
+ *
+ * public static void main(String[] args) {
+ * UntypedActorRef actor = UntypedActor.actorOf(SampleUntypedActor.class);
+ * actor.start();
+ * actor.sendOneWay("SendToSelf");
+ * actor.stop();
+ * }
+ * }
+ *
+ *
+ * @author Jonas Bonér
+ */
+abstract class UntypedActor extends Actor {
+ protected[akka] var context: Option[UntypedActorRef] = None
+
+ final protected def receive = {
+ case msg =>
+ if (context.isEmpty) {
+ val ctx = new UntypedActorRef(self)
+ context = Some(ctx)
+ onReceive(msg, ctx)
+ } else onReceive(msg, context.get)
+ }
+
+ @throws(classOf[Exception])
+ def onReceive(message: Any, context: UntypedActorRef): Unit
+}
+
+/**
+ * Implements the Transactor abstraction. E.g. a transactional UntypedActor.
+ *
+ * @author Jonas Bonér
+ */
+abstract class UntypedTransactor extends UntypedActor {
+ self.makeTransactionRequired
+}
+
+/**
+ * Extend this abstract class to create a remote UntypedActor.
+ *
+ * @author Jonas Bonér
+ */
+abstract class RemoteUntypedActor(address: InetSocketAddress) extends UntypedActor {
+ def this(hostname: String, port: Int) = this(new InetSocketAddress(hostname, port))
+ self.makeRemote(address)
+}
+
+/**
+ * Factory object for creating and managing 'UntypedActor's. Meant to be used from Java.
+ *
+ * Example on how to create an actor:
+ *
+ * You can create and start the actor in one statement like this:
+ *
+ * ActorRef actor = UntypedActor.actorOf(MyUntypedActor.class).start();
+ *
+ *
+ * @author Jonas Bonér
+ */
+object UntypedActor {
+
+ /**
+ * Creates an ActorRef out of the Actor. Allows you to pass in the class for the Actor.
+ *
+ * Example in Java:
+ *
+ * You can create and start the actor in one statement like this:
+ *
+ * ActorRef actor = UntypedActor.actorOf(MyUntypedActor.class).start();
+ *
+ */
+ def actorOf(clazz: Class[_]): UntypedActorRef = {
+ if (!clazz.isInstanceOf[Class[_ <: UntypedActor]]) throw new IllegalArgumentException(
+ "Class [" + clazz.getName + "] passed into the 'actorOf' factory method needs to be assignable from 'UntypedActor'")
+ UntypedActorRef.wrap(new LocalActorRef(() => clazz.newInstance.asInstanceOf[Actor]))
+ }
+
+ /**
+ * NOTE: Use this convenience method with care, do NOT make it possible to get a reference to the
+ * UntypedActor instance directly, but only through its 'UntypedActorRef' wrapper reference.
+ *
+ * Creates an ActorRef out of the Actor. Allows you to pass in the instance for the Actor. Only
+ * use this method when you need to pass in constructor arguments into the 'UntypedActor'.
+ *
+ * Example in Java:
+ *
+ * You can create and start the actor in one statement like this:
+ *
+ * ActorRef actor = UntypedActor.actorOf(MyUntypedActor.class).start();
+ *
+ */
+ def actorOf(actorInstance: UntypedActor): UntypedActorRef = UntypedActorRef.wrap(new LocalActorRef(() => actorInstance))
+}
+
+/**
+ * Use this class if you need to wrap an 'ActorRef' in the more Java-friendly 'UntypedActorRef'.
+ *
+ * @author Jonas Bonér
+ */
+object UntypedActorRef {
+ def wrap(actorRef: ActorRef) = new UntypedActorRef(actorRef)
+}
+
+/**
+ * A Java-friendly wrapper class around the 'ActorRef'.
+ *
+ * @author Jonas Bonér
+ */
+class UntypedActorRef(val actorRef: ActorRef) {
+
+ /**
+ * Returns the uuid for the actor.
+ */
+ def getUuid(): String = actorRef.uuid
+
+ /**
+ * Identifier for actor, does not have to be a unique one. Default is the 'uuid'.
+ *
+ * This field is used for logging, AspectRegistry.actorsFor(id), identifier for remote
+ * actor in RemoteServer etc.But also as the identifier for persistence, which means
+ * that you can use a custom name to be able to retrieve the "correct" persisted state
+ * upon restart, remote restart etc.
+ */
+ def setId(id: String) = actorRef.id = id
+ def getId(): String = actorRef.id
+
+ /**
+ * Defines the default timeout for '!!' and '!!!' invocations,
+ * e.g. the timeout for the future returned by the call to '!!' and '!!!'.
+ */
+ def setTimeout(timeout: Long) = actorRef.timeout = timeout
+ def getTimeout(): Long = actorRef.timeout
+
+ /**
+ * Defines the default timeout for an initial receive invocation.
+ * When specified, the receive function should be able to handle a 'ReceiveTimeout' message.
+ */
+ def setReceiveTimeout(timeout: Long) = actorRef.receiveTimeout = Some(timeout)
+ def getReceiveTimeout(): Option[Long] = actorRef.receiveTimeout
+
+ /**
+ * Set 'trapExit' to the list of exception classes that the actor should be able to trap
+ * from the actor it is supervising. When the supervising actor throws these exceptions
+ * then they will trigger a restart.
+ *
+ *
+ * Trap all exceptions:
+ *
+ */
+ def setTrapExit(exceptions: Array[Class[_ <: Throwable]]) = actorRef.trapExit = exceptions.toList
+ def getTrapExit(): Array[Class[_ <: Throwable]] = actorRef.trapExit.toArray
+
+ /**
+ * If 'trapExit' is set for the actor to act as supervisor, then a 'faultHandler' must be defined.
+ *
+ * Can be one of:
+ *
+ */
+ def setFaultHandler(handler: FaultHandlingStrategy) = actorRef.faultHandler = Some(handler)
+ def getFaultHandler(): Option[FaultHandlingStrategy] = actorRef.faultHandler
+
+ /**
+ * Defines the life-cycle for a supervised actor.
+ */
+ def setLifeCycle(lifeCycle: LifeCycle) = actorRef.lifeCycle = Some(lifeCycle)
+ def getLifeCycle(): Option[LifeCycle] = actorRef.lifeCycle
+
+ /**
+ * The default dispatcher is the Dispatchers.globalExecutorBasedEventDrivenDispatcher();.
+ * This means that all actors will share the same event-driven executor based dispatcher.
+ *
+ * You can override it so it fits the specific use-case that the actor is used for.
+ * See the se.scalablesolutions.akka.dispatch.Dispatchers class for the different
+ * dispatchers available.
+ *
+ * The default is also that all actors that are created and spawned from within this actor
+ * is sharing the same dispatcher as its creator.
+ */
+ def setDispatcher(dispatcher: MessageDispatcher) = actorRef.dispatcher = dispatcher
+ def getDispatcher(): MessageDispatcher = actorRef.dispatcher
+
+ /**
+ * The reference sender Actor of the last received message.
+ * Is defined if the message was sent from another Actor, else None.
+ */
+ def getSender(): Option[UntypedActorRef] = actorRef.sender match {
+ case Some(s) => Some(UntypedActorRef.wrap(s))
+ case None => None
+ }
+
+ /**
+ * The reference sender future of the last received message.
+ * Is defined if the message was sent with sent with 'sendRequestReply' or 'sendRequestReplyFuture', else None.
+ */
+ def getSenderFuture(): Option[CompletableFuture[Any]] = actorRef.senderFuture
+
+ /**
+ * Starts up the actor and its message queue.
+ */
+ def start(): UntypedActorRef = UntypedActorRef.wrap(actorRef.start)
+
+ /**
+ * Shuts down the actor its dispatcher and message queue.
+ * Alias for 'stop'.
+ */
+ def exit() = stop()
+
+ /**
+ * Shuts down the actor its dispatcher and message queue.
+ */
+ def stop(): Unit = actorRef.stop()
+
+ /**
+ * Sends a one-way asynchronous message. E.g. fire-and-forget semantics.
+ *
+ *
+ * actor.sendOneWay(message);
+ *
+ *
+ */
+ def sendOneWay(message: AnyRef) = actorRef.!(message)(None)
+
+ /**
+ * Sends a one-way asynchronous message. E.g. fire-and-forget semantics.
+ *
+ * Allows you to pass along the sender of the messag.
+ *
+ *
+ * actor.sendOneWay(message, context);
+ *
+ *
+ */
+ def sendOneWay(message: AnyRef, sender: UntypedActorRef) =
+ if (sender eq null) actorRef.!(message)(None)
+ else actorRef.!(message)(Some(sender.actorRef))
+
+ /**
+ * Sends a message asynchronously and waits on a future for a reply message under the hood. The timeout is taken from
+ * the default timeout in the Actor.
+ *
+ * It waits on the reply either until it receives it or until the timeout expires
+ * (which will throw an ActorTimeoutException). E.g. send-and-receive-eventually semantics.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReply then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReply(message: AnyRef): AnyRef =
+ actorRef.!!(message)(None).getOrElse(throw new ActorTimeoutException(
+ "Message [" + message +
+ "]\n\tsent to [" + actorRef.actorClassName +
+ "]\n\twith timeout [" + actorRef.timeout +
+ "]\n\ttimed out."))
+ .asInstanceOf[AnyRef]
+
+ /**
+ * Sends a message asynchronously and waits on a future for a reply message under the hood. The timeout is taken from
+ * the default timeout in the Actor.
+ *
+ * It waits on the reply either until it receives it or until the timeout expires
+ * (which will throw an ActorTimeoutException). E.g. send-and-receive-eventually semantics.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReply then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReply(message: AnyRef, sender: UntypedActorRef): AnyRef = {
+ val result = if (sender eq null) actorRef.!!(message)(None)
+ else actorRef.!!(message)(Some(sender.actorRef))
+ result.getOrElse(throw new ActorTimeoutException(
+ "Message [" + message +
+ "]\n\tsent to [" + actorRef.actorClassName +
+ "]\n\tfrom [" + sender.actorRef.actorClassName +
+ "]\n\twith timeout [" + actorRef.timeout +
+ "]\n\ttimed out."))
+ .asInstanceOf[AnyRef]
+ }
+
+ /**
+ * Sends a message asynchronously and waits on a future for a reply message under the hood.
+ *
+ * It waits on the reply either until it receives it or until the timeout expires
+ * (which will throw an ActorTimeoutException). E.g. send-and-receive-eventually semantics.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReply then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReply(message: AnyRef, timeout: Long): AnyRef =
+ actorRef.!!(message, timeout)(None).getOrElse(throw new ActorTimeoutException(
+ "Message [" + message +
+ "]\n\tsent to [" + actorRef.actorClassName +
+ "]\n\twith timeout [" + timeout +
+ "]\n\ttimed out."))
+ .asInstanceOf[AnyRef]
+
+ /**
+ * Sends a message asynchronously and waits on a future for a reply message under the hood.
+ *
+ * It waits on the reply either until it receives it or until the timeout expires
+ * (which will throw an ActorTimeoutException). E.g. send-and-receive-eventually semantics.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReply then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReply(message: AnyRef, timeout: Long, sender: UntypedActorRef): AnyRef = {
+ val result = if (sender eq null) actorRef.!!(message, timeout)(None)
+ else actorRef.!!(message)(Some(sender.actorRef))
+ result.getOrElse(throw new ActorTimeoutException(
+ "Message [" + message +
+ "]\n\tsent to [" + actorRef.actorClassName +
+ "]\n\tfrom [" + sender.actorRef.actorClassName +
+ "]\n\twith timeout [" + timeout +
+ "]\n\ttimed out."))
+ .asInstanceOf[AnyRef]
+ }
+
+ /**
+ * Sends a message asynchronously returns a future holding the eventual reply message. The timeout is taken from
+ * the default timeout in the Actor.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with the 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReplyFuture then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReplyFuture(message: AnyRef): Future[_] = actorRef.!!!(message)(None)
+
+ /**
+ * Sends a message asynchronously returns a future holding the eventual reply message. The timeout is taken from
+ * the default timeout in the Actor.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with the 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReplyFuture then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReplyFuture(message: AnyRef, sender: UntypedActorRef): Future[_] =
+ if (sender eq null) actorRef.!!!(message)(None)
+ else actorRef.!!!(message)(Some(sender.actorRef))
+
+ /**
+ * Sends a message asynchronously returns a future holding the eventual reply message.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with the 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReplyFuture then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReplyFuture(message: AnyRef, timeout: Long): Future[_] = actorRef.!!!(message, timeout)(None)
+
+ /**
+ * Sends a message asynchronously returns a future holding the eventual reply message.
+ *
+ * NOTE:
+ * Use this method with care. In most cases it is better to use 'sendOneWay' together with the 'context.getSender()' to
+ * implement request/response message exchanges.
+ *
+ * If you are sending messages using sendRequestReplyFuture then you have to use context.reply(..)
+ * to send a reply message to the original sender. If not then the sender will block until the timeout expires.
+ */
+ def sendRequestReplyFuture(message: AnyRef, timeout: Long, sender: UntypedActorRef): Future[_] =
+ if (sender eq null) actorRef.!!!(message, timeout)(None)
+ else actorRef.!!!(message)(Some(sender.actorRef))
+
+ /**
+ * Forwards the message and passes the original sender actor as the sender.
+ *
+ * Works with 'sendOneWay', 'sendRequestReply' and 'sendRequestReplyFuture'.
+ */
+ def forward(message: AnyRef, sender: UntypedActorRef): Unit =
+ if (sender eq null) throw new IllegalArgumentException("The 'sender' argument to 'forward' can't be null")
+ else actorRef.forward(message)(Some(sender.actorRef))
+
+ /**
+ * Use context.replyUnsafe(..) to reply with a message to the original sender of the message currently
+ * being processed.
+ *
+ * Throws an IllegalStateException if unable to determine what to reply to.
+ */
+ def replyUnsafe(message: AnyRef): Unit = actorRef.reply(message)
+
+ /**
+ * Use context.replySafe(..) to reply with a message to the original sender of the message currently
+ * being processed.
+ *
+ * Returns true if reply was sent, and false if unable to determine what to reply to.
+ */
+ def replySafe(message: AnyRef): Boolean = actorRef.reply_?(message)
+
+ /**
+ * Returns the class for the Actor instance that is managed by the ActorRef.
+ */
+ def getActorClass(): Class[_ <: Actor] = actorRef.actorClass
+
+ /**
+ * Returns the class name for the Actor instance that is managed by the ActorRef.
+ */
+ def getActorClassName(): String = actorRef.actorClassName
+
+ /**
+ * Invoking 'makeRemote' means that an actor will be moved to and invoked on a remote host.
+ */
+ def makeRemote(hostname: String, port: Int): Unit = actorRef.makeRemote(hostname, port)
+
+ /**
+ * Invoking 'makeRemote' means that an actor will be moved to and invoked on a remote host.
+ */
+ def makeRemote(address: InetSocketAddress): Unit = actorRef.makeRemote(address)
+
+ /**
+ * Invoking 'makeTransactionRequired' means that the actor will **start** a new transaction if non exists.
+ * However, it will always participate in an existing transaction.
+ */
+ def makeTransactionRequired(): Unit = actorRef.makeTransactionRequired
+
+ /**
+ * Sets the transaction configuration for this actor. Needs to be invoked before the actor is started.
+ */
+ def setTransactionConfig(config: TransactionConfig): Unit = actorRef.transactionConfig = config
+
+ /**
+ * Get the transaction configuration for this actor.
+ */
+ def getTransactionConfig(): TransactionConfig = actorRef.transactionConfig
+
+ /**
+ * Gets the remote address for the actor, if any, else None.
+ */
+ def getRemoteAddress(): Option[InetSocketAddress] = actorRef.remoteAddress
+
+ /**
+ * Returns the home address and port for this actor.
+ */
+ def getHomeAddress(): InetSocketAddress = actorRef.homeAddress
+
+ /**
+ * Set the home address and port for this actor.
+ */
+ def setHomeAddress(hostnameAndPort: Tuple2[String, Int]): Unit = actorRef.homeAddress = hostnameAndPort
+
+ /**
+ * Set the home address and port for this actor.
+ */
+ def setHomeAddress(address: InetSocketAddress): Unit = actorRef.homeAddress = address
+
+ /**
+ * Links an other actor to this actor. Links are unidirectional and means that a the linking actor will
+ * receive a notification if the linked actor has crashed.
+ *
+ * If the 'trapExit' member field has been set to at contain at least one exception class then it will
+ * 'trap' these exceptions and automatically restart the linked actors according to the restart strategy
+ * defined by the 'faultHandler'.
+ */
+ def link(actor: UntypedActorRef): Unit = actorRef.link(actor.actorRef)
+
+ /**
+ * Unlink the actor.
+ */
+ def unlink(actor: UntypedActorRef): Unit = actorRef.unlink(actor.actorRef)
+
+ /**
+ * Atomically start and link an actor.
+ */
+ def startLink(actor: UntypedActorRef): Unit = actorRef.startLink(actor.actorRef)
+
+ /**
+ * Atomically start, link and make an actor remote.
+ */
+ def startLinkRemote(actor: UntypedActorRef, hostname: String, port: Int): Unit =
+ actorRef.startLinkRemote(actor.actorRef, hostname, port)
+
+ /**
+ * Returns the mailbox size.
+ */
+ def getMailboxSize(): Int = actorRef.mailboxSize
+
+ /**
+ * Returns the current supervisor if there is one, null if not.
+ */
+ def getSupervisor(): UntypedActorRef = UntypedActorRef.wrap(actorRef.supervisor.getOrElse(null))
+}
diff --git a/akka-core/src/main/scala/config/Config.scala b/akka-core/src/main/scala/config/Config.scala
index 68842ad1e3..ec44453e59 100644
--- a/akka-core/src/main/scala/config/Config.scala
+++ b/akka-core/src/main/scala/config/Config.scala
@@ -82,6 +82,8 @@ object Config extends Logging {
if (VERSION != CONFIG_VERSION) throw new ConfigurationException(
"Akka JAR version [" + VERSION + "] is different than the provided config ('akka.conf') version [" + CONFIG_VERSION + "]")
+ val TIME_UNIT = config.getString("akka.time-unit", "seconds")
+
val startTime = System.currentTimeMillis
def uptime = (System.currentTimeMillis - startTime) / 1000
}
diff --git a/akka-core/src/main/scala/config/Configuration.scala b/akka-core/src/main/scala/config/Configuration.scala
index faa5c912f1..e257c739a9 100644
--- a/akka-core/src/main/scala/config/Configuration.scala
+++ b/akka-core/src/main/scala/config/Configuration.scala
@@ -5,7 +5,7 @@
package se.scalablesolutions.akka.config
/*
-import se.scalablesolutions.akka.kernel.{ActiveObject, ActiveObjectProxy}
+import se.scalablesolutions.akka.kernel.{TypedActor, TypedActorProxy}
import com.google.inject.{AbstractModule}
import java.util.{List => JList, ArrayList}
import scala.reflect.BeanProperty
@@ -55,6 +55,6 @@ class Component(@BeanProperty val intf: Class[_],
@BeanProperty val target: Class[_],
@BeanProperty val lifeCycle: LifeCycle,
@BeanProperty val timeout: Int) extends Server {
- def newWorker(proxy: ActiveObjectProxy) = se.scalablesolutions.akka.kernel.Supervise(proxy.server, lifeCycle.transform)
+ def newWorker(proxy: TypedActorProxy) = se.scalablesolutions.akka.kernel.Supervise(proxy.server, lifeCycle.transform)
}
*/
diff --git a/akka-core/src/main/scala/config/Configurator.scala b/akka-core/src/main/scala/config/Configurator.scala
index db92c5f35b..ba7e1f35f2 100644
--- a/akka-core/src/main/scala/config/Configurator.scala
+++ b/akka-core/src/main/scala/config/Configurator.scala
@@ -6,14 +6,14 @@ package se.scalablesolutions.akka.config
import ScalaConfig.{RestartStrategy, Component}
-private[akka] trait ActiveObjectConfiguratorBase {
+private[akka] trait TypedActorConfiguratorBase {
def getExternalDependency[T](clazz: Class[T]): T
- def configure(restartStrategy: RestartStrategy, components: List[Component]): ActiveObjectConfiguratorBase
+ def configure(restartStrategy: RestartStrategy, components: List[Component]): TypedActorConfiguratorBase
- def inject: ActiveObjectConfiguratorBase
+ def inject: TypedActorConfiguratorBase
- def supervise: ActiveObjectConfiguratorBase
+ def supervise: TypedActorConfiguratorBase
def reset
diff --git a/akka-core/src/main/scala/config/SupervisionConfig.scala b/akka-core/src/main/scala/config/SupervisionConfig.scala
index 1f5fd15a9b..cb0829704d 100644
--- a/akka-core/src/main/scala/config/SupervisionConfig.scala
+++ b/akka-core/src/main/scala/config/SupervisionConfig.scala
@@ -42,16 +42,7 @@ object ScalaConfig {
case object AllForOne extends FailOverScheme
case object OneForOne extends FailOverScheme
- case class LifeCycle(scope: Scope,
- restartCallbacks: Option[RestartCallbacks] = None,
- shutdownCallback: Option[ShutdownCallback] = None) extends ConfigElement
- case class RestartCallbacks(preRestart: String, postRestart: String) {
- if ((preRestart eq null) || (postRestart eq null)) throw new IllegalArgumentException("Restart callback methods can't be null")
- }
- case class ShutdownCallback(shutdown: String) {
- if (shutdown eq null) throw new IllegalArgumentException("Shutdown callback method can't be null")
- }
-
+ case class LifeCycle(scope: Scope) extends ConfigElement
case object Permanent extends Scope
case object Temporary extends Scope
@@ -137,26 +128,12 @@ object JavaConfig {
scheme.transform, maxNrOfRetries, withinTimeRange, trapExceptions.toList)
}
- class LifeCycle(@BeanProperty val scope: Scope,
- @BeanProperty val restartCallbacks: RestartCallbacks,
- @BeanProperty val shutdownCallback: ShutdownCallback) extends ConfigElement {
- def this(scope: Scope) = this(scope, null, null)
- def this(scope: Scope, restartCallbacks: RestartCallbacks) = this(scope, restartCallbacks, null)
- def this(scope: Scope, shutdownCallback: ShutdownCallback) = this(scope, null, shutdownCallback)
+ class LifeCycle(@BeanProperty val scope: Scope) extends ConfigElement {
def transform = {
- val restartCallbacksOption = if (restartCallbacks eq null) None else Some(restartCallbacks.transform)
- val shutdownCallbackOption = if (shutdownCallback eq null) None else Some(shutdownCallback.transform)
- se.scalablesolutions.akka.config.ScalaConfig.LifeCycle(scope.transform, restartCallbacksOption, shutdownCallbackOption)
+ se.scalablesolutions.akka.config.ScalaConfig.LifeCycle(scope.transform)
}
}
- class RestartCallbacks(@BeanProperty val preRestart: String, @BeanProperty val postRestart: String) {
- def transform = se.scalablesolutions.akka.config.ScalaConfig.RestartCallbacks(preRestart, postRestart)
- }
- class ShutdownCallback(@BeanProperty val shutdown: String) {
- def transform = se.scalablesolutions.akka.config.ScalaConfig.ShutdownCallback(shutdown)
- }
-
abstract class Scope extends ConfigElement {
def transform: se.scalablesolutions.akka.config.ScalaConfig.Scope
}
diff --git a/akka-core/src/main/scala/config/ActiveObjectConfigurator.scala b/akka-core/src/main/scala/config/TypedActorConfigurator.scala
similarity index 56%
rename from akka-core/src/main/scala/config/ActiveObjectConfigurator.scala
rename to akka-core/src/main/scala/config/TypedActorConfigurator.scala
index 88e495bbd0..d639d21f5f 100644
--- a/akka-core/src/main/scala/config/ActiveObjectConfigurator.scala
+++ b/akka-core/src/main/scala/config/TypedActorConfigurator.scala
@@ -12,54 +12,55 @@ import java.util.{ArrayList}
import com.google.inject._
/**
- * Configurator for the Active Objects. Used to do declarative configuration of supervision.
- * It also does dependency injection with and into Active Objects using dependency injection
+ * Configurator for the TypedActors. Used to do declarative configuration of supervision.
+ * It also does dependency injection with and into TypedActors using dependency injection
* frameworks such as Google Guice or Spring.
*
- * If you don't want declarative configuration then you should use the ActiveObject
+ * If you don't want declarative configuration then you should use the TypedActor
* factory methods.
*
* @author Jonas Bonér
*/
-class ActiveObjectConfigurator {
+class TypedActorConfigurator {
import scala.collection.JavaConversions._
// TODO: make pluggable once we have f.e a SpringConfigurator
- private val INSTANCE = new ActiveObjectGuiceConfigurator
+ private val INSTANCE = new TypedActorGuiceConfigurator
/**
- * Returns the a list with all active objects that has been put under supervision for the class specified.
+ * Returns the a list with all typed actors that has been put under supervision for the class specified.
*
- * @param clazz the class for the active object
- * @return a list with all the active objects for the class
+ * @param clazz the class for the typed actor
+ * @return a list with all the typed actors for the class
*/
- def getInstances[T](clazz: Class[T]): JList[T] = INSTANCE.getInstance(clazz).foldLeft(new ArrayList[T]){ (l, i) => l add i ; l }
+ def getInstances[T](clazz: Class[T]): JList[T] =
+ INSTANCE.getInstance(clazz).foldLeft(new ArrayList[T]){ (l, i) => l add i ; l }
/**
- * Returns the first item in a list of all active objects that has been put under supervision for the class specified.
+ * Returns the first item in a list of all typed actors that has been put under supervision for the class specified.
*
- * @param clazz the class for the active object
- * @return the active object for the class
+ * @param clazz the class for the typed actor
+ * @return the typed actor for the class
*/
def getInstance[T](clazz: Class[T]): T = INSTANCE.getInstance(clazz).head
- def configure(restartStrategy: RestartStrategy, components: Array[Component]): ActiveObjectConfigurator = {
+ def configure(restartStrategy: RestartStrategy, components: Array[Component]): TypedActorConfigurator = {
INSTANCE.configure(
restartStrategy.transform,
components.toList.asInstanceOf[scala.List[Component]].map(_.transform))
this
}
- def inject: ActiveObjectConfigurator = {
+ def inject: TypedActorConfigurator = {
INSTANCE.inject
this
}
- def supervise: ActiveObjectConfigurator = {
+ def supervise: TypedActorConfigurator = {
INSTANCE.supervise
this
}
- def addExternalGuiceModule(module: Module): ActiveObjectConfigurator = {
+ def addExternalGuiceModule(module: Module): TypedActorConfigurator = {
INSTANCE.addExternalGuiceModule(module)
this
}
diff --git a/akka-core/src/main/scala/config/ActiveObjectGuiceConfigurator.scala b/akka-core/src/main/scala/config/TypedActorGuiceConfigurator.scala
similarity index 66%
rename from akka-core/src/main/scala/config/ActiveObjectGuiceConfigurator.scala
rename to akka-core/src/main/scala/config/TypedActorGuiceConfigurator.scala
index 54174b6030..8b23921792 100644
--- a/akka-core/src/main/scala/config/ActiveObjectGuiceConfigurator.scala
+++ b/akka-core/src/main/scala/config/TypedActorGuiceConfigurator.scala
@@ -7,7 +7,7 @@ package se.scalablesolutions.akka.config
import com.google.inject._
import se.scalablesolutions.akka.config.ScalaConfig._
-import se.scalablesolutions.akka.actor.{Supervisor, ActiveObject, Dispatcher, ActorRef, Actor, IllegalActorStateException}
+import se.scalablesolutions.akka.actor.{Supervisor, TypedActor, Dispatcher, ActorRef, Actor, IllegalActorStateException}
import se.scalablesolutions.akka.remote.RemoteServer
import se.scalablesolutions.akka.util.Logging
@@ -17,12 +17,12 @@ import java.net.InetSocketAddress
import java.lang.reflect.Method
/**
- * This is an class for internal usage. Instead use the se.scalablesolutions.akka.config.ActiveObjectConfigurator
- * class for creating ActiveObjects.
+ * This is an class for internal usage. Instead use the se.scalablesolutions.akka.config.TypedActorConfigurator
+ * class for creating TypedActors.
*
* @author Jonas Bonér
*/
-private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfiguratorBase with Logging {
+private[akka] class TypedActorGuiceConfigurator extends TypedActorConfiguratorBase with Logging {
private var injector: Injector = _
private var supervisor: Option[Supervisor] = None
private var restartStrategy: RestartStrategy = _
@@ -30,22 +30,22 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
private var supervised: List[Supervise] = Nil
private var bindings: List[DependencyBinding] = Nil
private var configRegistry = new HashMap[Class[_], Component] // TODO is configRegistry needed?
- private var activeObjectRegistry = new HashMap[Class[_], Tuple3[AnyRef, AnyRef, Component]]
+ private var typedActorRegistry = new HashMap[Class[_], Tuple3[AnyRef, AnyRef, Component]]
private var modules = new java.util.ArrayList[Module]
private var methodToUriRegistry = new HashMap[Method, String]
/**
* Returns the active abject that has been put under supervision for the class specified.
*
- * @param clazz the class for the active object
- * @return the active objects for the class
+ * @param clazz the class for the typed actor
+ * @return the typed actors for the class
*/
def getInstance[T](clazz: Class[T]): List[T] = synchronized {
- log.debug("Retrieving active object [%s]", clazz.getName)
+ log.debug("Retrieving typed actor [%s]", clazz.getName)
if (injector eq null) throw new IllegalActorStateException(
"inject() and/or supervise() must be called before invoking getInstance(clazz)")
val (proxy, targetInstance, component) =
- activeObjectRegistry.getOrElse(clazz, throw new IllegalActorStateException(
+ typedActorRegistry.getOrElse(clazz, throw new IllegalActorStateException(
"Class [" + clazz.getName + "] has not been put under supervision" +
"\n(by passing in the config to the 'configure' and then invoking 'supervise') method"))
injector.injectMembers(targetInstance)
@@ -53,7 +53,7 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
}
def isDefined(clazz: Class[_]): Boolean = synchronized {
- activeObjectRegistry.get(clazz).isDefined
+ typedActorRegistry.get(clazz).isDefined
}
override def getExternalDependency[T](clazz: Class[T]): T = synchronized {
@@ -67,7 +67,7 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
}
override def configure(restartStrategy: RestartStrategy, components: List[Component]):
- ActiveObjectConfiguratorBase = synchronized {
+ TypedActorConfiguratorBase = synchronized {
this.restartStrategy = restartStrategy
this.components = components.toArray.toList.asInstanceOf[List[Component]]
bindings = for (component <- this.components) yield {
@@ -76,63 +76,72 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
}
val deps = new java.util.ArrayList[DependencyBinding](bindings.size)
for (b <- bindings) deps.add(b)
- modules.add(new ActiveObjectGuiceModule(deps))
+ modules.add(new TypedActorGuiceModule(deps))
this
}
private def newSubclassingProxy(component: Component): DependencyBinding = {
- val targetClass = component.target
- val actorRef = Actor.actorOf(new Dispatcher(component.transactionRequired,
- component.lifeCycle.restartCallbacks,
- component.lifeCycle.shutdownCallback))
+ val targetClass =
+ if (component.target.isInstanceOf[Class[_ <: TypedActor]]) component.target.asInstanceOf[Class[_ <: TypedActor]]
+ else throw new IllegalArgumentException("TypedActor [" + component.target.getName + "] must be a subclass of TypedActor")
+ val actorRef = Actor.actorOf(new Dispatcher(component.transactionRequired))
if (component.dispatcher.isDefined) actorRef.dispatcher = component.dispatcher.get
val remoteAddress =
if (component.remoteAddress.isDefined)
Some(new InetSocketAddress(component.remoteAddress.get.hostname, component.remoteAddress.get.port))
else None
- val proxy = ActiveObject.newInstance(targetClass, actorRef, remoteAddress, component.timeout).asInstanceOf[AnyRef]
- remoteAddress.foreach(address => RemoteServer.registerActiveObject(address, targetClass.getName, proxy))
+ val proxy = TypedActor.newInstance(targetClass, actorRef, remoteAddress, component.timeout).asInstanceOf[AnyRef]
+ remoteAddress.foreach(address => RemoteServer.registerTypedActor(address, targetClass.getName, proxy))
supervised ::= Supervise(actorRef, component.lifeCycle)
- activeObjectRegistry.put(targetClass, (proxy, proxy, component))
+ typedActorRegistry.put(targetClass, (proxy, proxy, component))
new DependencyBinding(targetClass, proxy)
}
private def newDelegatingProxy(component: Component): DependencyBinding = {
- val targetClass = component.intf.get
- val targetInstance = component.target.newInstance.asInstanceOf[AnyRef] // TODO: perhaps need to put in registry
component.target.getConstructor(Array[Class[_]](): _*).setAccessible(true)
- val actorRef = Actor.actorOf(new Dispatcher(component.transactionRequired,
- component.lifeCycle.restartCallbacks,
- component.lifeCycle.shutdownCallback))
+
+ val targetClass = component.intf.get
+ val instance = component.target.newInstance.asInstanceOf[AnyRef] // TODO: perhaps need to put in registry
+
+ val targetInstance =
+ if (instance.isInstanceOf[TypedActor]) instance.asInstanceOf[TypedActor]
+ else throw new IllegalArgumentException("TypedActor [" + component.target.getName + "] must be a subclass of TypedActor")
+
+ val actorRef = Actor.actorOf(new Dispatcher(component.transactionRequired))
+
if (component.dispatcher.isDefined) actorRef.dispatcher = component.dispatcher.get
+
val remoteAddress =
if (component.remoteAddress.isDefined)
Some(new InetSocketAddress(component.remoteAddress.get.hostname, component.remoteAddress.get.port))
else None
- val proxy = ActiveObject.newInstance(
+
+ val proxy = TypedActor.newInstance(
targetClass, targetInstance, actorRef, remoteAddress, component.timeout).asInstanceOf[AnyRef]
- remoteAddress.foreach(address => RemoteServer.registerActiveObject(address, targetClass.getName, proxy))
+
+ remoteAddress.foreach(address => RemoteServer.registerTypedActor(address, targetClass.getName, proxy))
supervised ::= Supervise(actorRef, component.lifeCycle)
- activeObjectRegistry.put(targetClass, (proxy, targetInstance, component))
+
+ typedActorRegistry.put(targetClass, (proxy, targetInstance, component))
new DependencyBinding(targetClass, proxy)
}
- override def inject: ActiveObjectConfiguratorBase = synchronized {
+ override def inject: TypedActorConfiguratorBase = synchronized {
if (injector ne null) throw new IllegalActorStateException("inject() has already been called on this configurator")
injector = Guice.createInjector(modules)
this
}
- override def supervise: ActiveObjectConfiguratorBase = synchronized {
+ override def supervise: TypedActorConfiguratorBase = synchronized {
if (injector eq null) inject
- supervisor = Some(ActiveObject.supervise(restartStrategy, supervised))
+ supervisor = Some(TypedActor.supervise(restartStrategy, supervised))
this
}
/**
* Add additional services to be wired in.
*
*/
- def addExternalGuiceModule(module: Module): ActiveObjectConfiguratorBase = synchronized {
+ def addExternalGuiceModule(module: Module): TypedActorConfiguratorBase = synchronized {
modules.add(module)
this
}
@@ -151,7 +160,7 @@ private[akka] class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurat
def reset = synchronized {
modules = new java.util.ArrayList[Module]
configRegistry = new HashMap[Class[_], Component]
- activeObjectRegistry = new HashMap[Class[_], Tuple3[AnyRef, AnyRef, Component]]
+ typedActorRegistry = new HashMap[Class[_], Tuple3[AnyRef, AnyRef, Component]]
methodToUriRegistry = new HashMap[Method, String]
injector = null
restartStrategy = null
diff --git a/akka-core/src/main/scala/dispatch/AbstractReactorBasedEventDrivenDispatcher.scala b/akka-core/src/main/scala/dispatch/AbstractReactorBasedEventDrivenDispatcher.scala
index 832ae9203a..6bacec73be 100644
--- a/akka-core/src/main/scala/dispatch/AbstractReactorBasedEventDrivenDispatcher.scala
+++ b/akka-core/src/main/scala/dispatch/AbstractReactorBasedEventDrivenDispatcher.scala
@@ -29,6 +29,7 @@ abstract class AbstractReactorBasedEventDrivenDispatcher(val name: String) exten
}
def shutdown = if (active) {
+ log.debug("Shutting down %s", toString)
active = false
selectorThread.interrupt
doShutdown
diff --git a/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenDispatcher.scala b/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenDispatcher.scala
index 48b42847a0..836dc0ea86 100644
--- a/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenDispatcher.scala
+++ b/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenDispatcher.scala
@@ -5,6 +5,7 @@
package se.scalablesolutions.akka.dispatch
import se.scalablesolutions.akka.actor.{ActorRef, IllegalActorStateException}
+import jsr166x.ConcurrentLinkedDeque
/**
* Default settings are:
@@ -64,18 +65,37 @@ class ExecutorBasedEventDrivenDispatcher(_name: String, throughput: Int = Dispat
@volatile private var active: Boolean = false
- val name: String = "event-driven:executor:dispatcher:" + _name
+ val name = "akka:event-driven:dispatcher:" + _name
init
- def dispatch(invocation: MessageInvocation) = dispatch(invocation.receiver)
+ def dispatch(invocation: MessageInvocation) = {
+ getMailbox(invocation.receiver).add(invocation)
+ dispatch(invocation.receiver)
+ }
+
+ /**
+ * @return the mailbox associated with the actor
+ */
+ private def getMailbox(receiver: ActorRef) = receiver.mailbox.asInstanceOf[ConcurrentLinkedDeque[MessageInvocation]]
+
+ override def mailboxSize(actorRef: ActorRef) = getMailbox(actorRef).size
+
+ override def register(actorRef: ActorRef) = {
+ // The actor will need a ConcurrentLinkedDeque based mailbox
+ if( actorRef.mailbox == null ) {
+ actorRef.mailbox = new ConcurrentLinkedDeque[MessageInvocation]()
+ }
+ super.register(actorRef)
+ }
def dispatch(receiver: ActorRef): Unit = if (active) {
+
executor.execute(new Runnable() {
def run = {
var lockAcquiredOnce = false
var finishedBeforeMailboxEmpty = false
val lock = receiver.dispatcherLock
- val mailbox = receiver.mailbox
+ val mailbox = getMailbox(receiver)
// this do-while loop is required to prevent missing new messages between the end of the inner while
// loop and releasing the lock
do {
@@ -92,7 +112,9 @@ class ExecutorBasedEventDrivenDispatcher(_name: String, throughput: Int = Dispat
} while ((lockAcquiredOnce && !finishedBeforeMailboxEmpty && !mailbox.isEmpty))
}
})
- } else throw new IllegalActorStateException("Can't submit invocations to dispatcher since it's not started")
+ } else {
+ log.warning("%s is shut down,\n\tignoring the rest of the messages in the mailbox of\n\t%s", toString, receiver)
+ }
/**
@@ -102,39 +124,38 @@ class ExecutorBasedEventDrivenDispatcher(_name: String, throughput: Int = Dispat
*/
def processMailbox(receiver: ActorRef): Boolean = {
var processedMessages = 0
- var messageInvocation = receiver.mailbox.poll
+ val mailbox = getMailbox(receiver)
+ var messageInvocation = mailbox.poll
while (messageInvocation != null) {
messageInvocation.invoke
processedMessages += 1
// check if we simply continue with other messages, or reached the throughput limit
- if (throughput <= 0 || processedMessages < throughput)
- messageInvocation = receiver.mailbox.poll
+ if (throughput <= 0 || processedMessages < throughput) messageInvocation = mailbox.poll
else {
- return !receiver.mailbox.isEmpty
messageInvocation = null
+ return !mailbox.isEmpty
}
}
-
- return false
+ false
}
def start = if (!active) {
- log.debug("Starting ExecutorBasedEventDrivenDispatcher [%s]", name)
- log.debug("Throughput for %s = %d", name, throughput)
+ log.debug("Starting up %s\n\twith throughput [%d]", toString, throughput)
active = true
}
def shutdown = if (active) {
- log.debug("Shutting down ExecutorBasedEventDrivenDispatcher [%s]", name)
+ log.debug("Shutting down %s", toString)
executor.shutdownNow
active = false
references.clear
}
- def usesActorMailbox = true
-
def ensureNotActive(): Unit = if (active) throw new IllegalActorStateException(
"Can't build a new thread pool for a dispatcher that is already up and running")
+ override def toString = "ExecutorBasedEventDrivenDispatcher[" + name + "]"
+
+ // FIXME: should we have an unbounded queue and not bounded as default ????
private[akka] def init = withNewThreadPoolWithLinkedBlockingQueueWithUnboundedCapacity.buildThreadPool
}
diff --git a/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala b/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala
index 94ef0a2e67..b9ff5d92f4 100644
--- a/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala
+++ b/akka-core/src/main/scala/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala
@@ -7,6 +7,7 @@ package se.scalablesolutions.akka.dispatch
import java.util.concurrent.CopyOnWriteArrayList
import se.scalablesolutions.akka.actor.{Actor, ActorRef, IllegalActorStateException}
+import jsr166x.ConcurrentLinkedDeque
/**
* An executor based event driven dispatcher which will try to redistribute work from busy actors to idle actors. It is assumed
@@ -41,11 +42,19 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
/** The index in the pooled actors list which was last used to steal work */
@volatile private var lastThiefIndex = 0
- // TODO: is there a naming convention for this name?
- val name: String = "event-driven-work-stealing:executor:dispatcher:" + _name
+ val name = "akka:event-driven-work-stealing:dispatcher:" + _name
init
+
+ /**
+ * @return the mailbox associated with the actor
+ */
+ private def getMailbox(receiver: ActorRef) = receiver.mailbox.asInstanceOf[ConcurrentLinkedDeque[MessageInvocation]]
+
+ override def mailboxSize(actorRef: ActorRef) = getMailbox(actorRef).size
+
def dispatch(invocation: MessageInvocation) = if (active) {
+ getMailbox(invocation.receiver).add(invocation)
executor.execute(new Runnable() {
def run = {
if (!tryProcessMailbox(invocation.receiver)) {
@@ -77,7 +86,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
lock.unlock
}
}
- } while ((lockAcquiredOnce && !receiver.mailbox.isEmpty))
+ } while ((lockAcquiredOnce && !getMailbox(receiver).isEmpty))
return lockAcquiredOnce
}
@@ -86,10 +95,11 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
* Process the messages in the mailbox of the given actor.
*/
private def processMailbox(receiver: ActorRef) = {
- var messageInvocation = receiver.mailbox.poll
+ val mailbox = getMailbox(receiver)
+ var messageInvocation = mailbox.poll
while (messageInvocation != null) {
messageInvocation.invoke
- messageInvocation = receiver.mailbox.poll
+ messageInvocation = mailbox.poll
}
}
@@ -117,7 +127,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
for (i <- 0 to actors.length) {
val index = (i + startIndex) % actors.length
val actor = actors(index)
- if (actor != receiver && actor.mailbox.isEmpty) return (Some(actor), index)
+ if (actor != receiver && getMailbox(actor).isEmpty) return (Some(actor), index)
}
(None, startIndex) // nothing found, reuse same start index next time
}
@@ -129,8 +139,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
private def tryDonateAndProcessMessages(receiver: ActorRef, thief: ActorRef) = {
if (thief.dispatcherLock.tryLock) {
try {
- while(donateMessage(receiver, thief))
- processMailbox(thief)
+ while(donateMessage(receiver, thief)) processMailbox(thief)
} finally {
thief.dispatcherLock.unlock
}
@@ -141,7 +150,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
* Steal a message from the receiver and give it to the thief.
*/
private def donateMessage(receiver: ActorRef, thief: ActorRef): Boolean = {
- val donated = receiver.mailbox.pollLast
+ val donated = getMailbox(receiver).pollLast
if (donated ne null) {
if (donated.senderFuture.isDefined) thief.self.postMessageToMailboxAndCreateFutureResultWithTimeout[Any](
donated.message, receiver.timeout, donated.sender, donated.senderFuture)
@@ -156,7 +165,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
}
def shutdown = if (active) {
- log.debug("Shutting down ExecutorBasedEventDrivenWorkStealingDispatcher [%s]", name)
+ log.debug("Shutting down %s", toString)
executor.shutdownNow
active = false
references.clear
@@ -165,10 +174,16 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
def ensureNotActive(): Unit = if (active) throw new IllegalActorStateException(
"Can't build a new thread pool for a dispatcher that is already up and running")
+ override def toString = "ExecutorBasedEventDrivenWorkStealingDispatcher[" + name + "]"
+
private[akka] def init = withNewThreadPoolWithLinkedBlockingQueueWithUnboundedCapacity.buildThreadPool
override def register(actorRef: ActorRef) = {
verifyActorsAreOfSameType(actorRef)
+ // The actor will need a ConcurrentLinkedDeque based mailbox
+ if( actorRef.mailbox == null ) {
+ actorRef.mailbox = new ConcurrentLinkedDeque[MessageInvocation]()
+ }
pooledActors.add(actorRef)
super.register(actorRef)
}
@@ -178,19 +193,14 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(_name: String) extends Mess
super.unregister(actorRef)
}
- def usesActorMailbox = true
-
private def verifyActorsAreOfSameType(actorOfId: ActorRef) = {
actorType match {
- case None => {
- actorType = Some(actorOfId.actor.getClass)
- }
- case Some(aType) => {
+ case None => actorType = Some(actorOfId.actor.getClass)
+ case Some(aType) =>
if (aType != actorOfId.actor.getClass)
- throw new IllegalActorStateException(
- String.format("Can't register actor %s in a work stealing dispatcher which already knows actors of type %s",
- actorOfId.actor, aType))
- }
+ throw new IllegalActorStateException(String.format(
+ "Can't register actor %s in a work stealing dispatcher which already knows actors of type %s",
+ actorOfId.actor, aType))
}
}
}
diff --git a/akka-core/src/main/scala/dispatch/HawtDispatcher.scala b/akka-core/src/main/scala/dispatch/HawtDispatcher.scala
new file mode 100644
index 0000000000..45e4468b3d
--- /dev/null
+++ b/akka-core/src/main/scala/dispatch/HawtDispatcher.scala
@@ -0,0 +1,249 @@
+/**
+ * Copyright (C) 2010, Progress Software Corporation and/or its
+ * subsidiaries or affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package se.scalablesolutions.akka.dispatch
+
+import se.scalablesolutions.akka.actor.ActorRef
+import org.fusesource.hawtdispatch.DispatchQueue
+import org.fusesource.hawtdispatch.ScalaDispatch._
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.CountDownLatch
+import org.fusesource.hawtdispatch.DispatchQueue.QueueType
+import org.fusesource.hawtdispatch.ListEventAggregator
+
+/**
+ * Holds helper methods for working with actors that are using
+ * a HawtDispatcher as it's dispatcher.
+ */
+object HawtDispatcher {
+
+ private val retained = new AtomicInteger()
+ @volatile private var shutdownLatch: CountDownLatch = _
+
+ private def retainNonDaemon = {
+ if( retained.getAndIncrement == 0 ) {
+ shutdownLatch = new CountDownLatch(1)
+ new Thread("HawtDispatch Non-Daemon") {
+ override def run = {
+ try {
+ shutdownLatch.await
+ } catch {
+ case _ =>
+ }
+ println("done");
+ }
+ }.start()
+ }
+ }
+
+ private def releaseNonDaemon = {
+ if( retained.decrementAndGet == 0 ) {
+ shutdownLatch.countDown
+ shutdownLatch = null
+ }
+ }
+
+ /**
+ * @return the mailbox associated with the actor
+ */
+ private def mailbox(actorRef: ActorRef) = {
+ actorRef.mailbox.asInstanceOf[HawtDispatcherMailbox]
+ }
+
+ /**
+ * @return the dispatch queue associated with the actor
+ */
+ def queue(actorRef: ActorRef) = {
+ mailbox(actorRef).queue
+ }
+
+
+ /**
+ *
+ * Pins an actor to a random thread queue. Once pinned the actor will always execute
+ * on the same thread.
+ *
+ *
+ *
+ * This method can only succeed if the actor it's dispatcher is set to a HawtDispatcher and it has been started
+ *
+ *
+ * @return true if the actor was pinned
+ */
+ def pin(actorRef: ActorRef) = {
+ actorRef.mailbox match {
+ case x:HawtDispatcherMailbox=>
+ x.queue.setTargetQueue( getRandomThreadQueue )
+ true
+ case _ => false
+ }
+ }
+
+ /**
+ *
+ * Unpins the actor so that all threads in the hawt dispatch thread pool
+ * compete to execute him.
+ *
+ *
+ *
+ * This method can only succeed if the actor it's dispatcher is set to a HawtDispatcher and it has been started
+ *
+ * @return true if the actor was unpinned
+ */
+ def unpin(actorRef: ActorRef) = {
+ target(actorRef, globalQueue)
+ }
+
+
+ /**
+ * @return true if the actor was pinned to a thread.
+ */
+ def pinned(actorRef: ActorRef):Boolean = {
+ actorRef.mailbox match {
+ case x:HawtDispatcherMailbox=>
+ x.queue.getTargetQueue.getQueueType == QueueType.THREAD_QUEUE
+ case _ => false
+ }
+ }
+
+ /**
+ *
+ * Updates the actor's target dispatch queue to the value specified. This allows
+ * you to do odd things like targeting another serial queue.
+ *
+ *
+ *
+ * This method can only succeed if the actor it's dispatcher is set to a HawtDispatcher and it has been started
+ *
+ * @return true if the actor was unpinned
+ */
+ def target(actorRef: ActorRef, parent:DispatchQueue) = {
+ actorRef.mailbox match {
+ case x:HawtDispatcherMailbox=>
+ x.queue.setTargetQueue( parent )
+ true
+ case _ => false
+ }
+ }
+
+}
+
+/**
+ *
+ * A HawtDispatch based MessageDispatcher. Actors with this dispatcher are executed
+ * on the HawtDispatch fixed sized thread pool. The number of of threads will match
+ * the number of cores available on your system.
+ *
+ *
+ *
+ * Actors using this dispatcher are restricted to only executing non blocking
+ * operations. The actor cannot synchronously call another actor or call 3rd party
+ * libraries that can block for a long time. You should use non blocking IO APIs
+ * instead of blocking IO apis to avoid blocking that actor for an extended amount
+ * of time.
+ *
+ *
+ *
+ * This dispatcher delivers messages to the actors in the order that they
+ * were producer at the sender.
+ *
+ *
+ *
+ * HawtDispatch supports processing Non blocking Socket IO in both the reactor
+ * and proactor styles. For more details, see the HawtDispacherEchoServer.scala
+ * example.
+ *
+ *
+ * @author Hiram Chirino
+ */
+class HawtDispatcher(val aggregate:Boolean=true, val parent:DispatchQueue=globalQueue) extends MessageDispatcher {
+ import HawtDispatcher._
+ private val active = new AtomicBoolean(false)
+
+ def start = {
+ if( active.compareAndSet(false, true) ) {
+ retainNonDaemon
+ }
+ }
+
+ def shutdown = {
+ if( active.compareAndSet(true, false) ) {
+ releaseNonDaemon
+ }
+ }
+
+ def isShutdown = !active.get
+
+ def dispatch(invocation: MessageInvocation) = if(active.get()) {
+ mailbox(invocation.receiver).dispatch(invocation)
+ } else {
+ log.warning("%s is shut down,\n\tignoring the the messages sent to\n\t%s", toString, invocation.receiver)
+ }
+
+ // hawtdispatch does not have a way to get queue sizes, getting an accurate
+ // size can cause extra contention.. is this really needed?
+ // TODO: figure out if this can be optional in akka
+ override def mailboxSize(actorRef: ActorRef) = 0
+
+ override def register(actorRef: ActorRef) = {
+ if( actorRef.mailbox == null ) {
+ val queue = parent.createSerialQueue(actorRef.toString)
+ if( aggregate ) {
+ actorRef.mailbox = new AggregatingHawtDispatcherMailbox(queue)
+ } else {
+ actorRef.mailbox = new HawtDispatcherMailbox(queue)
+ }
+ }
+ super.register(actorRef)
+ }
+
+ override def toString = "HawtDispatchEventDrivenDispatcher"
+
+}
+
+class HawtDispatcherMailbox(val queue:DispatchQueue) {
+ def dispatch(invocation: MessageInvocation):Unit = {
+ queue {
+ invocation.invoke
+ }
+ }
+}
+
+class AggregatingHawtDispatcherMailbox(queue:DispatchQueue) extends HawtDispatcherMailbox(queue) {
+ private val source = createSource(new ListEventAggregator[MessageInvocation](), queue)
+ source.setEventHandler (^{drain_source} )
+ source.resume
+
+ private def drain_source = {
+ source.getData.foreach { invocation =>
+ invocation.invoke
+ }
+ }
+
+ override def dispatch(invocation: MessageInvocation):Unit = {
+ if ( getCurrentQueue == null ) {
+ // we are being call from a non hawtdispatch thread, can't aggregate
+ // it's events
+ super.dispatch(invocation)
+ } else {
+ // we are being call from a hawtdispatch thread, use the dispatch source
+ // so that multiple invocations issues on this thread will aggregate and then once
+ // the thread runs out of work, they get transferred as a batch to the other thread.
+ source.merge(invocation)
+ }
+ }
+}
diff --git a/akka-core/src/main/scala/dispatch/MessageHandling.scala b/akka-core/src/main/scala/dispatch/MessageHandling.scala
index c2e74ceb1d..92926bb253 100644
--- a/akka-core/src/main/scala/dispatch/MessageHandling.scala
+++ b/akka-core/src/main/scala/dispatch/MessageHandling.scala
@@ -53,7 +53,7 @@ final class MessageInvocation(val receiver: ActorRef,
"\n\tsender = " + sender +
"\n\tsenderFuture = " + senderFuture +
"\n\ttransactionSet = " + transactionSet +
- "\n]"
+ "]"
}
}
@@ -79,7 +79,7 @@ trait MessageDispatcher extends Logging {
}
def canBeShutDown: Boolean = references.isEmpty
def isShutdown: Boolean
- def usesActorMailbox : Boolean
+ def mailboxSize(actorRef: ActorRef):Int = 0
}
/**
diff --git a/akka-core/src/main/scala/dispatch/ReactorBasedSingleThreadEventDrivenDispatcher.scala b/akka-core/src/main/scala/dispatch/ReactorBasedSingleThreadEventDrivenDispatcher.scala
index e8fbe9a221..d0850aa830 100644
--- a/akka-core/src/main/scala/dispatch/ReactorBasedSingleThreadEventDrivenDispatcher.scala
+++ b/akka-core/src/main/scala/dispatch/ReactorBasedSingleThreadEventDrivenDispatcher.scala
@@ -12,11 +12,14 @@ package se.scalablesolutions.akka.dispatch
import java.util.{LinkedList, List}
-class ReactorBasedSingleThreadEventDrivenDispatcher(name: String) extends AbstractReactorBasedEventDrivenDispatcher(name) {
+class ReactorBasedSingleThreadEventDrivenDispatcher(_name: String)
+ extends AbstractReactorBasedEventDrivenDispatcher("akka:event-driven:reactor:single-thread:dispatcher:" + _name) {
+
def start = if (!active) {
+ log.debug("Starting up %s", toString)
active = true
val messageDemultiplexer = new Demultiplexer(queue)
- selectorThread = new Thread("event-driven:reactor:single-thread:dispatcher:" + name) {
+ selectorThread = new Thread(name) {
override def run = {
while (active) {
try {
@@ -38,7 +41,7 @@ class ReactorBasedSingleThreadEventDrivenDispatcher(name: String) extends Abstra
def isShutdown = !active
- def usesActorMailbox = false
+ override def toString = "ReactorBasedSingleThreadEventDrivenDispatcher[" + name + "]"
class Demultiplexer(private val messageQueue: ReactiveMessageQueue) extends MessageDemultiplexer {
diff --git a/akka-core/src/main/scala/dispatch/ReactorBasedThreadPoolEventDrivenDispatcher.scala b/akka-core/src/main/scala/dispatch/ReactorBasedThreadPoolEventDrivenDispatcher.scala
index 3e44cf9f6a..530184d4b2 100644
--- a/akka-core/src/main/scala/dispatch/ReactorBasedThreadPoolEventDrivenDispatcher.scala
+++ b/akka-core/src/main/scala/dispatch/ReactorBasedThreadPoolEventDrivenDispatcher.scala
@@ -64,7 +64,7 @@ import se.scalablesolutions.akka.actor.IllegalActorStateException
* @author Jonas Bonér
*/
class ReactorBasedThreadPoolEventDrivenDispatcher(_name: String)
- extends AbstractReactorBasedEventDrivenDispatcher("event-driven:reactor:thread-pool:dispatcher:" + _name)
+ extends AbstractReactorBasedEventDrivenDispatcher("akka:event-driven:reactor:dispatcher:" + _name)
with ThreadPoolBuilder {
private var fair = true
@@ -75,17 +75,18 @@ class ReactorBasedThreadPoolEventDrivenDispatcher(_name: String)
withNewThreadPoolWithLinkedBlockingQueueWithUnboundedCapacity.buildThreadPool
def start = if (!active) {
+ log.debug("Starting up %s", toString)
active = true
/**
- * This dispatcher code is based on code from the actorom actor framework by Sergio Bossa [http://code.google.com/p/actorom/].
+ * This dispatcher code is based on code from the actorom actor framework by Sergio Bossa
+ * [http://code.google.com/p/actorom/].
*/
selectorThread = new Thread(name) {
override def run = {
while (active) {
try {
try {
- // guard.synchronized { /* empty */ } // prevents risk for deadlock as described in [http://developers.sun.com/learning/javaoneonline/2006/coreplatform/TS-1315.pdf]
messageDemultiplexer.select
} catch { case e: InterruptedException => active = false }
process(messageDemultiplexer.acquireSelectedInvocations)
@@ -110,7 +111,8 @@ class ReactorBasedThreadPoolEventDrivenDispatcher(_name: String)
if (invocation eq null) throw new IllegalActorStateException("Message invocation is null [" + invocation + "]")
if (!busyActors.contains(invocation.receiver)) {
val invoker = messageInvokers.get(invocation.receiver)
- if (invoker eq null) throw new IllegalActorStateException("Message invoker for invocation [" + invocation + "] is null")
+ if (invoker eq null) throw new IllegalActorStateException(
+ "Message invoker for invocation [" + invocation + "] is null")
resume(invocation.receiver)
invocations.remove
executor.execute(new Runnable() {
@@ -137,11 +139,11 @@ class ReactorBasedThreadPoolEventDrivenDispatcher(_name: String)
else nrOfBusyMessages < 100
}
- def usesActorMailbox = false
-
def ensureNotActive(): Unit = if (active) throw new IllegalActorStateException(
"Can't build a new thread pool for a dispatcher that is already up and running")
+ override def toString = "ReactorBasedThreadPoolEventDrivenDispatcher[" + name + "]"
+
class Demultiplexer(private val messageQueue: ReactiveMessageQueue) extends MessageDemultiplexer {
private val selectedInvocations: List[MessageInvocation] = new LinkedList[MessageInvocation]
private val selectedInvocationsLock = new ReentrantLock
diff --git a/akka-core/src/main/scala/dispatch/ThreadBasedDispatcher.scala b/akka-core/src/main/scala/dispatch/ThreadBasedDispatcher.scala
index 5c1cb78a52..012c4899d8 100644
--- a/akka-core/src/main/scala/dispatch/ThreadBasedDispatcher.scala
+++ b/akka-core/src/main/scala/dispatch/ThreadBasedDispatcher.scala
@@ -16,7 +16,7 @@ import se.scalablesolutions.akka.actor.{Actor, ActorRef}
*/
class ThreadBasedDispatcher(private val actor: ActorRef) extends MessageDispatcher {
private val name = actor.getClass.getName + ":" + actor.uuid
- private val threadName = "thread-based:dispatcher:" + name
+ private val threadName = "akka:thread-based:dispatcher:" + name
private val queue = new BlockingMessageQueue(name)
private var selectorThread: Thread = _
@volatile private var active: Boolean = false
@@ -24,6 +24,7 @@ class ThreadBasedDispatcher(private val actor: ActorRef) extends MessageDispatch
def dispatch(invocation: MessageInvocation) = queue.append(invocation)
def start = if (!active) {
+ log.debug("Starting up %s", toString)
active = true
selectorThread = new Thread(threadName) {
override def run = {
@@ -39,14 +40,14 @@ class ThreadBasedDispatcher(private val actor: ActorRef) extends MessageDispatch
def isShutdown = !active
- def usesActorMailbox = false
-
def shutdown = if (active) {
- log.debug("Shutting down ThreadBasedDispatcher [%s]", name)
+ log.debug("Shutting down %s", toString)
active = false
selectorThread.interrupt
references.clear
}
+
+ override def toString = "ThreadBasedDispatcher[" + threadName + "]"
}
class BlockingMessageQueue(name: String) extends MessageQueue {
diff --git a/akka-core/src/main/scala/dispatch/ThreadPoolBuilder.scala b/akka-core/src/main/scala/dispatch/ThreadPoolBuilder.scala
index a111ae87a5..5abf431ef8 100644
--- a/akka-core/src/main/scala/dispatch/ThreadPoolBuilder.scala
+++ b/akka-core/src/main/scala/dispatch/ThreadPoolBuilder.scala
@@ -234,18 +234,19 @@ trait ThreadPoolBuilder {
extends Thread(runnable, name + "-" + MonitorableThread.created.incrementAndGet) with Logging {
setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- def uncaughtException(thread: Thread, cause: Throwable) = log.error(cause, "UNCAUGHT in thread [%s]", thread.getName)
+ def uncaughtException(thread: Thread, cause: Throwable) =
+ log.error(cause, "UNCAUGHT in thread [%s]", thread.getName)
})
override def run = {
val debug = MonitorableThread.debugLifecycle
- log.debug("Created %s", getName)
+ log.debug("Created thread %s", getName)
try {
MonitorableThread.alive.incrementAndGet
super.run
} finally {
MonitorableThread.alive.decrementAndGet
- log.debug("Exiting %s", getName)
+ log.debug("Exiting thread %s", getName)
}
}
}
diff --git a/akka-core/src/main/scala/remote/Cluster.scala b/akka-core/src/main/scala/remote/Cluster.scala
index f1c3633944..8a5864a51b 100644
--- a/akka-core/src/main/scala/remote/Cluster.scala
+++ b/akka-core/src/main/scala/remote/Cluster.scala
@@ -151,11 +151,17 @@ abstract class BasicClusterActor extends ClusterActor with Logging {
case InitClusterActor(s) => {
serializer = s
+ boot
}
}
/**
- * Implement this in a subclass to add node-to-node messaging
+ * Implement this in a subclass to boot up the cluster implementation
+ */
+ protected def boot: Unit
+
+ /**
+ * Implement this in a subclass to add node-to-node messaging
*/
protected def toOneNode(dest: ADDR_T, msg: Array[Byte]): Unit
diff --git a/akka-core/src/main/scala/remote/JGroupsClusterActor.scala b/akka-core/src/main/scala/remote/JGroupsClusterActor.scala
index 847985e3d3..54ef3807d4 100644
--- a/akka-core/src/main/scala/remote/JGroupsClusterActor.scala
+++ b/akka-core/src/main/scala/remote/JGroupsClusterActor.scala
@@ -17,9 +17,8 @@ class JGroupsClusterActor extends BasicClusterActor {
@volatile private var isActive = false
@volatile private var channel: Option[JChannel] = None
- override def init = {
- super.init
- log info "Initiating JGroups-based cluster actor"
+ protected def boot = {
+ log info "Booting JGroups-based cluster"
isActive = true
// Set up the JGroups local endpoint
diff --git a/akka-core/src/main/scala/remote/RemoteClient.scala b/akka-core/src/main/scala/remote/RemoteClient.scala
index c90d472c09..e0212572b2 100644
--- a/akka-core/src/main/scala/remote/RemoteClient.scala
+++ b/akka-core/src/main/scala/remote/RemoteClient.scala
@@ -7,8 +7,8 @@ package se.scalablesolutions.akka.remote
import se.scalablesolutions.akka.remote.protocol.RemoteProtocol._
import se.scalablesolutions.akka.actor.{Exit, Actor, ActorRef, RemoteActorRef, IllegalActorStateException}
import se.scalablesolutions.akka.dispatch.{DefaultCompletableFuture, CompletableFuture}
-import se.scalablesolutions.akka.util.{UUID, Logging}
-import se.scalablesolutions.akka.config.Config.config
+import se.scalablesolutions.akka.util.{UUID, Logging, Duration}
+import se.scalablesolutions.akka.config.Config._
import org.jboss.netty.channel._
import group.DefaultChannelGroup
@@ -51,8 +51,8 @@ case class RemoteClientConnected(host: String, port: Int) extends RemoteClientLi
* @author Jonas Bonér
*/
object RemoteClient extends Logging {
- val READ_TIMEOUT = config.getInt("akka.remote.client.read-timeout", 10000)
- val RECONNECT_DELAY = config.getInt("akka.remote.client.reconnect-delay", 5000)
+ val READ_TIMEOUT = Duration(config.getInt("akka.remote.client.read-timeout", 1), TIME_UNIT)
+ val RECONNECT_DELAY = Duration(config.getInt("akka.remote.client.reconnect-delay", 5), TIME_UNIT)
private val remoteClients = new HashMap[String, RemoteClient]
private val remoteActors = new HashMap[RemoteServer.Address, HashSet[String]]
@@ -138,7 +138,7 @@ object RemoteClient extends Logging {
actorsFor(RemoteServer.Address(hostname, port)) += uuid
}
- // TODO: add RemoteClient.unregister for ActiveObject, but first need a @shutdown callback
+ // TODO: add RemoteClient.unregister for TypedActor, but first need a @shutdown callback
private[akka] def unregister(hostname: String, port: Int, uuid: String) = synchronized {
val set = actorsFor(RemoteServer.Address(hostname, port))
set -= uuid
@@ -218,7 +218,7 @@ class RemoteClient private[akka] (val hostname: String, val port: Int, loader: O
} else {
futures.synchronized {
val futureResult = if (senderFuture.isDefined) senderFuture.get
- else new DefaultCompletableFuture[T](request.getTimeout)
+ else new DefaultCompletableFuture[T](request.getActorInfo.getTimeout)
futures.put(request.getId, futureResult)
connection.getChannel.write(request)
Some(futureResult)
@@ -231,11 +231,13 @@ class RemoteClient private[akka] (val hostname: String, val port: Int, loader: O
}
private[akka] def registerSupervisorForActor(actorRef: ActorRef) =
- if (!actorRef.supervisor.isDefined) throw new IllegalActorStateException("Can't register supervisor for " + actorRef + " since it is not under supervision")
+ if (!actorRef.supervisor.isDefined) throw new IllegalActorStateException(
+ "Can't register supervisor for " + actorRef + " since it is not under supervision")
else supervisors.putIfAbsent(actorRef.supervisor.get.uuid, actorRef)
private[akka] def deregisterSupervisorForActor(actorRef: ActorRef) =
- if (!actorRef.supervisor.isDefined) throw new IllegalActorStateException("Can't unregister supervisor for " + actorRef + " since it is not under supervision")
+ if (!actorRef.supervisor.isDefined) throw new IllegalActorStateException(
+ "Can't unregister supervisor for " + actorRef + " since it is not under supervision")
else supervisors.remove(actorRef.supervisor.get.uuid)
}
@@ -250,6 +252,7 @@ class RemoteClientPipelineFactory(name: String,
timer: HashedWheelTimer,
client: RemoteClient) extends ChannelPipelineFactory {
def getPipeline: ChannelPipeline = {
+
def join(ch: ChannelHandler*) = Array[ChannelHandler](ch:_*)
val engine = RemoteServerSslContext.client.createSSLEngine()
@@ -257,7 +260,7 @@ class RemoteClientPipelineFactory(name: String,
engine.setUseClientMode(true)
val ssl = if(RemoteServer.SECURE) join(new SslHandler(engine)) else join()
- val timeout = new ReadTimeoutHandler(timer, RemoteClient.READ_TIMEOUT)
+ val timeout = new ReadTimeoutHandler(timer, RemoteClient.READ_TIMEOUT.toMillis.toInt)
val lenDec = new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4)
val lenPrep = new LengthFieldPrepender(4)
val protobufDec = new ProtobufDecoder(RemoteReplyProtocol.getDefaultInstance)
@@ -345,7 +348,7 @@ class RemoteClientHandler(val name: String,
log.error(client.connection.getCause, "Reconnection to [%s] has failed", remoteAddress)
}
}
- }, RemoteClient.RECONNECT_DELAY, TimeUnit.MILLISECONDS)
+ }, RemoteClient.RECONNECT_DELAY.toMillis, TimeUnit.MILLISECONDS)
}
override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = {
diff --git a/akka-core/src/main/scala/remote/RemoteServer.scala b/akka-core/src/main/scala/remote/RemoteServer.scala
index 93386311f2..5d25d81b75 100644
--- a/akka-core/src/main/scala/remote/RemoteServer.scala
+++ b/akka-core/src/main/scala/remote/RemoteServer.scala
@@ -13,7 +13,7 @@ import se.scalablesolutions.akka.actor._
import se.scalablesolutions.akka.actor.Actor._
import se.scalablesolutions.akka.util._
import se.scalablesolutions.akka.remote.protocol.RemoteProtocol._
-import se.scalablesolutions.akka.config.Config.config
+import se.scalablesolutions.akka.config.Config._
import org.jboss.netty.bootstrap.ServerBootstrap
import org.jboss.netty.channel._
@@ -57,7 +57,7 @@ object RemoteNode extends RemoteServer
/**
* For internal use only.
- * Holds configuration variables, remote actors, remote active objects and remote servers.
+ * Holds configuration variables, remote actors, remote typed actors and remote servers.
*
* @author Jonas Bonér
*/
@@ -65,7 +65,7 @@ object RemoteServer {
val HOSTNAME = config.getString("akka.remote.server.hostname", "localhost")
val PORT = config.getInt("akka.remote.server.port", 9999)
- val CONNECTION_TIMEOUT_MILLIS = config.getInt("akka.remote.server.connection-timeout", 1000)
+ val CONNECTION_TIMEOUT_MILLIS = Duration(config.getInt("akka.remote.server.connection-timeout", 1), TIME_UNIT)
val COMPRESSION_SCHEME = config.getString("akka.remote.compression-scheme", "zlib")
val ZLIB_COMPRESSION_LEVEL = {
@@ -76,7 +76,8 @@ object RemoteServer {
}
val SECURE = {
- if(config.getBool("akka.remote.ssl.service",false)){
+ //TODO: Remove this when SSL is in working condition
+ /*if(config.getBool("akka.remote.ssl.service",false)){
val properties = List(
("key-store-type" ,"keyStoreType"),
@@ -97,7 +98,7 @@ object RemoteServer {
true
}
- else
+ else */
false
}
@@ -121,7 +122,7 @@ object RemoteServer {
private class RemoteActorSet {
private[RemoteServer] val actors = new ConcurrentHashMap[String, ActorRef]
- private[RemoteServer] val activeObjects = new ConcurrentHashMap[String, AnyRef]
+ private[RemoteServer] val typedActors = new ConcurrentHashMap[String, AnyRef]
}
private val guard = new ReadWriteGuard
@@ -132,8 +133,8 @@ object RemoteServer {
actorsFor(RemoteServer.Address(address.getHostName, address.getPort)).actors.put(uuid, actor)
}
- private[akka] def registerActiveObject(address: InetSocketAddress, name: String, activeObject: AnyRef) = guard.withWriteGuard {
- actorsFor(RemoteServer.Address(address.getHostName, address.getPort)).activeObjects.put(name, activeObject)
+ private[akka] def registerTypedActor(address: InetSocketAddress, name: String, typedActor: AnyRef) = guard.withWriteGuard {
+ actorsFor(RemoteServer.Address(address.getHostName, address.getPort)).typedActors.put(name, typedActor)
}
private[akka] def getOrCreateServer(address: InetSocketAddress): RemoteServer = guard.withWriteGuard {
@@ -225,12 +226,12 @@ class RemoteServer extends Logging {
RemoteServer.register(hostname, port, this)
val remoteActorSet = RemoteServer.actorsFor(RemoteServer.Address(hostname, port))
val pipelineFactory = new RemoteServerPipelineFactory(
- name, openChannels, loader, remoteActorSet.actors, remoteActorSet.activeObjects)
+ name, openChannels, loader, remoteActorSet.actors, remoteActorSet.typedActors)
bootstrap.setPipelineFactory(pipelineFactory)
bootstrap.setOption("child.tcpNoDelay", true)
bootstrap.setOption("child.keepAlive", true)
bootstrap.setOption("child.reuseAddress", true)
- bootstrap.setOption("child.connectTimeoutMillis", RemoteServer.CONNECTION_TIMEOUT_MILLIS)
+ bootstrap.setOption("child.connectTimeoutMillis", RemoteServer.CONNECTION_TIMEOUT_MILLIS.toMillis)
openChannels.add(bootstrap.bind(new InetSocketAddress(hostname, port)))
_isRunning = true
Cluster.registerLocalNode(hostname, port)
@@ -243,15 +244,20 @@ class RemoteServer extends Logging {
def shutdown = synchronized {
if (_isRunning) {
- RemoteServer.unregister(hostname, port)
- openChannels.disconnect
- openChannels.close.awaitUninterruptibly
- bootstrap.releaseExternalResources
- Cluster.deregisterLocalNode(hostname, port)
+ try {
+ RemoteServer.unregister(hostname, port)
+ openChannels.disconnect
+ openChannels.close.awaitUninterruptibly
+ bootstrap.releaseExternalResources
+ Cluster.deregisterLocalNode(hostname, port)
+ } catch {
+ case e: java.nio.channels.ClosedChannelException => {}
+ case e => log.warning("Could not close remote server channel in a graceful way")
+ }
}
}
- // TODO: register active object in RemoteServer as well
+ // TODO: register typed actor in RemoteServer as well
/**
* Register Remote Actor by the Actor's 'id' field. It starts the Actor if it is not started already.
@@ -331,7 +337,7 @@ class RemoteServerPipelineFactory(
val openChannels: ChannelGroup,
val loader: Option[ClassLoader],
val actors: JMap[String, ActorRef],
- val activeObjects: JMap[String, AnyRef]) extends ChannelPipelineFactory {
+ val typedActors: JMap[String, AnyRef]) extends ChannelPipelineFactory {
import RemoteServer._
def getPipeline: ChannelPipeline = {
@@ -351,7 +357,7 @@ class RemoteServerPipelineFactory(
case _ => (join(),join())
}
- val remoteServer = new RemoteServerHandler(name, openChannels, loader, actors, activeObjects)
+ val remoteServer = new RemoteServerHandler(name, openChannels, loader, actors, typedActors)
val stages = ssl ++ dec ++ join(lenDec, protobufDec) ++ enc ++ join(lenPrep, protobufEnc, remoteServer)
@@ -368,7 +374,7 @@ class RemoteServerHandler(
val openChannels: ChannelGroup,
val applicationLoader: Option[ClassLoader],
val actors: JMap[String, ActorRef],
- val activeObjects: JMap[String, AnyRef]) extends SimpleChannelUpstreamHandler with Logging {
+ val typedActors: JMap[String, AnyRef]) extends SimpleChannelUpstreamHandler with Logging {
val AW_PROXY_PREFIX = "$$ProxiedByAW".intern
applicationLoader.foreach(MessageSerializer.setClassLoader(_))
@@ -422,139 +428,88 @@ class RemoteServerHandler(
private def handleRemoteRequestProtocol(request: RemoteRequestProtocol, channel: Channel) = {
log.debug("Received RemoteRequestProtocol[\n%s]", request.toString)
- if (request.getIsActor) dispatchToActor(request, channel)
- else dispatchToActiveObject(request, channel)
+ val actorType = request.getActorInfo.getActorType
+ if (actorType == ActorType.SCALA_ACTOR) dispatchToActor(request, channel)
+ else if (actorType == ActorType.JAVA_ACTOR) throw new IllegalActorStateException("ActorType JAVA_ACTOR is currently not supported")
+ else if (actorType == ActorType.TYPED_ACTOR) dispatchToTypedActor(request, channel)
+ else throw new IllegalActorStateException("Unknown ActorType [" + actorType + "]")
}
private def dispatchToActor(request: RemoteRequestProtocol, channel: Channel) = {
- log.debug("Dispatching to remote actor [%s:%s]", request.getTarget, request.getUuid)
- val actorRef = createActor(request.getTarget, request.getUuid, request.getTimeout)
+ val actorInfo = request.getActorInfo
+ log.debug("Dispatching to remote actor [%s:%s]", actorInfo.getTarget, actorInfo.getUuid)
+
+ val actorRef = createActor(actorInfo)
actorRef.start
+
val message = MessageSerializer.deserialize(request.getMessage)
val sender =
if (request.hasSender) Some(RemoteActorSerialization.fromProtobufToRemoteActorRef(request.getSender, applicationLoader))
else None
+
if (request.getIsOneWay) actorRef.!(message)(sender)
else {
try {
val resultOrNone = (actorRef.!!(message)(sender)).as[AnyRef]
val result = if (resultOrNone.isDefined) resultOrNone.get else null
+
log.debug("Returning result from actor invocation [%s]", result)
val replyBuilder = RemoteReplyProtocol.newBuilder
.setId(request.getId)
.setMessage(MessageSerializer.serialize(result))
.setIsSuccessful(true)
.setIsActor(true)
+
if (request.hasSupervisorUuid) replyBuilder.setSupervisorUuid(request.getSupervisorUuid)
- val replyMessage = replyBuilder.build
- channel.write(replyMessage)
+ channel.write(replyBuilder.build)
+
} catch {
- case e: Throwable =>
- log.error(e, "Could not invoke remote actor [%s]", request.getTarget)
- val replyBuilder = RemoteReplyProtocol.newBuilder
- .setId(request.getId)
- .setException(ExceptionProtocol.newBuilder.setClassname(e.getClass.getName).setMessage(e.getMessage).build)
- .setIsSuccessful(false)
- .setIsActor(true)
- if (request.hasSupervisorUuid) replyBuilder.setSupervisorUuid(request.getSupervisorUuid)
- val replyMessage = replyBuilder.build
- channel.write(replyMessage)
+ case e: Throwable => channel.write(createErrorReplyMessage(e, request, true))
}
}
}
- private def dispatchToActiveObject(request: RemoteRequestProtocol, channel: Channel) = {
- log.debug("Dispatching to remote active object [%s :: %s]", request.getMethod, request.getTarget)
- val activeObject = createActiveObject(request.getTarget, request.getTimeout)
+ private def dispatchToTypedActor(request: RemoteRequestProtocol, channel: Channel) = {
+ val actorInfo = request.getActorInfo
+ val typedActorInfo = actorInfo.getTypedActorInfo
+ log.debug("Dispatching to remote typed actor [%s :: %s]", typedActorInfo.getMethod, typedActorInfo.getInterface)
+ val typedActor = createTypedActor(actorInfo)
val args = MessageSerializer.deserialize(request.getMessage).asInstanceOf[Array[AnyRef]].toList
val argClasses = args.map(_.getClass)
- val (unescapedArgs, unescapedArgClasses) = unescapeArgs(args, argClasses, request.getTimeout)
try {
- val messageReceiver = activeObject.getClass.getDeclaredMethod(
- request.getMethod, unescapedArgClasses: _*)
- if (request.getIsOneWay) messageReceiver.invoke(activeObject, unescapedArgs: _*)
+ val messageReceiver = typedActor.getClass.getDeclaredMethod(typedActorInfo.getMethod, argClasses: _*)
+ if (request.getIsOneWay) messageReceiver.invoke(typedActor, args: _*)
else {
- val result = messageReceiver.invoke(activeObject, unescapedArgs: _*)
- log.debug("Returning result from remote active object invocation [%s]", result)
+ val result = messageReceiver.invoke(typedActor, args: _*)
+ log.debug("Returning result from remote typed actor invocation [%s]", result)
val replyBuilder = RemoteReplyProtocol.newBuilder
.setId(request.getId)
.setMessage(MessageSerializer.serialize(result))
.setIsSuccessful(true)
.setIsActor(false)
if (request.hasSupervisorUuid) replyBuilder.setSupervisorUuid(request.getSupervisorUuid)
- val replyMessage = replyBuilder.build
- channel.write(replyMessage)
+ channel.write(replyBuilder.build)
}
} catch {
- case e: InvocationTargetException =>
- log.error(e.getCause, "Could not invoke remote active object [%s :: %s]", request.getMethod, request.getTarget)
- val replyBuilder = RemoteReplyProtocol.newBuilder
- .setId(request.getId)
- .setException(ExceptionProtocol.newBuilder.setClassname(e.getCause.getClass.getName).setMessage(e.getCause.getMessage).build)
- .setIsSuccessful(false)
- .setIsActor(false)
- if (request.hasSupervisorUuid) replyBuilder.setSupervisorUuid(request.getSupervisorUuid)
- val replyMessage = replyBuilder.build
- channel.write(replyMessage)
- case e: Throwable =>
- log.error(e, "Could not invoke remote active object [%s :: %s]", request.getMethod, request.getTarget)
- val replyBuilder = RemoteReplyProtocol.newBuilder
- .setId(request.getId)
- .setException(ExceptionProtocol.newBuilder.setClassname(e.getClass.getName).setMessage(e.getMessage).build)
- .setIsSuccessful(false)
- .setIsActor(false)
- if (request.hasSupervisorUuid) replyBuilder.setSupervisorUuid(request.getSupervisorUuid)
- val replyMessage = replyBuilder.build
- channel.write(replyMessage)
+ case e: InvocationTargetException => channel.write(createErrorReplyMessage(e.getCause, request, false))
+ case e: Throwable => channel.write(createErrorReplyMessage(e, request, false))
}
}
- private def unescapeArgs(args: scala.List[AnyRef], argClasses: scala.List[Class[_]], timeout: Long) = {
- val unescapedArgs = new Array[AnyRef](args.size)
- val unescapedArgClasses = new Array[Class[_]](args.size)
-
- val escapedArgs = for (i <- 0 until args.size) {
- val arg = args(i)
- if (arg.isInstanceOf[String] && arg.asInstanceOf[String].startsWith(AW_PROXY_PREFIX)) {
- val argString = arg.asInstanceOf[String]
- val proxyName = argString.replace(AW_PROXY_PREFIX, "")
- val activeObject = createActiveObject(proxyName, timeout)
- unescapedArgs(i) = activeObject
- unescapedArgClasses(i) = Class.forName(proxyName)
- } else {
- unescapedArgs(i) = args(i)
- unescapedArgClasses(i) = argClasses(i)
- }
- }
- (unescapedArgs, unescapedArgClasses)
- }
-
- private def createActiveObject(name: String, timeout: Long): AnyRef = {
- val activeObjectOrNull = activeObjects.get(name)
- if (activeObjectOrNull eq null) {
- try {
- log.info("Creating a new remote active object [%s]", name)
- val clazz = if (applicationLoader.isDefined) applicationLoader.get.loadClass(name)
- else Class.forName(name)
- val newInstance = ActiveObject.newInstance(clazz, timeout).asInstanceOf[AnyRef]
- activeObjects.put(name, newInstance)
- newInstance
- } catch {
- case e =>
- log.error(e, "Could not create remote active object instance")
- throw e
- }
- } else activeObjectOrNull
- }
-
/**
* Creates a new instance of the actor with name, uuid and timeout specified as arguments.
+ *
* If actor already created then just return it from the registry.
+ *
* Does not start the actor.
*/
- private def createActor(name: String, uuid: String, timeout: Long): ActorRef = {
+ private def createActor(actorInfo: ActorInfoProtocol): ActorRef = {
+ val name = actorInfo.getTarget
+ val uuid = actorInfo.getUuid
+ val timeout = actorInfo.getTimeout
+
val actorRefOrNull = actors.get(uuid)
if (actorRefOrNull eq null) {
try {
@@ -574,4 +529,43 @@ class RemoteServerHandler(
}
} else actorRefOrNull
}
+
+ private def createTypedActor(actorInfo: ActorInfoProtocol): AnyRef = {
+ val uuid = actorInfo.getUuid
+ val typedActorOrNull = typedActors.get(uuid)
+
+ if (typedActorOrNull eq null) {
+ val typedActorInfo = actorInfo.getTypedActorInfo
+ val interfaceClassname = typedActorInfo.getInterface
+ val targetClassname = actorInfo.getTarget
+
+ try {
+ log.info("Creating a new remote typed actor:\n\t[%s :: %s]", interfaceClassname, targetClassname)
+
+ val (interfaceClass, targetClass) =
+ if (applicationLoader.isDefined) (applicationLoader.get.loadClass(interfaceClassname),
+ applicationLoader.get.loadClass(targetClassname))
+ else (Class.forName(interfaceClassname), Class.forName(targetClassname))
+
+ val newInstance = TypedActor.newInstance(
+ interfaceClass, targetClass.asInstanceOf[Class[_ <: TypedActor]], actorInfo.getTimeout).asInstanceOf[AnyRef]
+ typedActors.put(uuid, newInstance)
+ newInstance
+ } catch {
+ case e => log.error(e, "Could not create remote typed actor instance"); throw e
+ }
+ } else typedActorOrNull
+ }
+
+ private def createErrorReplyMessage(e: Throwable, request: RemoteRequestProtocol, isActor: Boolean): RemoteReplyProtocol = {
+ val actorInfo = request.getActorInfo
+ log.error(e, "Could not invoke remote typed actor [%s :: %s]", actorInfo.getTypedActorInfo.getMethod, actorInfo.getTarget)
+ val replyBuilder = RemoteReplyProtocol.newBuilder
+ .setId(request.getId)
+ .setException(ExceptionProtocol.newBuilder.setClassname(e.getClass.getName).setMessage(e.getMessage).build)
+ .setIsSuccessful(false)
+ .setIsActor(isActor)
+ if (request.hasSupervisorUuid) replyBuilder.setSupervisorUuid(request.getSupervisorUuid)
+ replyBuilder.build
+ }
}
diff --git a/akka-core/src/main/scala/stm/JTA.scala b/akka-core/src/main/scala/stm/JTA.scala
index bb61973c91..1c0af88d73 100644
--- a/akka-core/src/main/scala/stm/JTA.scala
+++ b/akka-core/src/main/scala/stm/JTA.scala
@@ -4,7 +4,9 @@
package se.scalablesolutions.akka.stm
-import javax.transaction.{TransactionManager, UserTransaction, Transaction => JtaTransaction, SystemException, Status, Synchronization, TransactionSynchronizationRegistry}
+import javax.transaction.{TransactionManager, UserTransaction,
+ Transaction => JtaTransaction, SystemException,
+ Status, Synchronization, TransactionSynchronizationRegistry}
import javax.naming.{InitialContext, Context, NamingException}
import se.scalablesolutions.akka.config.Config._
@@ -16,7 +18,7 @@ import se.scalablesolutions.akka.util.Logging
* @author Jonas Bonér
*/
object TransactionContainer extends Logging {
- val AKKA_JTA_TRANSACTION_SERVICE_CLASS = "se.scalablesolutions.akka.jta.AtomikosTransactionService"
+ val AKKA_JTA_TRANSACTION_SERVICE_CLASS = "se.scalablesolutions.akka.jta.AtomikosTransactionService"
val DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction"
val FALLBACK_TRANSACTION_MANAGER_NAMES = "java:comp/TransactionManager" ::
"java:appserver/TransactionManager" ::
@@ -119,22 +121,31 @@ class TransactionContainer private (val tm: Either[Option[UserTransaction], Opti
}
}
- def begin = tm match {
- case Left(Some(userTx)) => userTx.begin
- case Right(Some(txMan)) => txMan.begin
- case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope")
+ def begin = {
+ TransactionContainer.log.ifTrace("Starting JTA transaction")
+ tm match {
+ case Left(Some(userTx)) => userTx.begin
+ case Right(Some(txMan)) => txMan.begin
+ case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope")
+ }
}
- def commit = tm match {
- case Left(Some(userTx)) => userTx.commit
- case Right(Some(txMan)) => txMan.commit
- case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope")
+ def commit = {
+ TransactionContainer.log.ifTrace("Committing JTA transaction")
+ tm match {
+ case Left(Some(userTx)) => userTx.commit
+ case Right(Some(txMan)) => txMan.commit
+ case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope")
+ }
}
- def rollback = tm match {
- case Left(Some(userTx)) => userTx.rollback
- case Right(Some(txMan)) => txMan.rollback
- case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope")
+ def rollback = {
+ TransactionContainer.log.ifTrace("Aborting JTA transaction")
+ tm match {
+ case Left(Some(userTx)) => userTx.rollback
+ case Right(Some(txMan)) => txMan.rollback
+ case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope")
+ }
}
def getStatus = tm match {
diff --git a/akka-core/src/main/scala/stm/Ref.scala b/akka-core/src/main/scala/stm/Ref.scala
index 3b13d32971..2ca6802b15 100644
--- a/akka-core/src/main/scala/stm/Ref.scala
+++ b/akka-core/src/main/scala/stm/Ref.scala
@@ -6,23 +6,15 @@ package se.scalablesolutions.akka.stm
import se.scalablesolutions.akka.util.UUID
-import org.multiverse.api.GlobalStmInstance.getGlobalStmInstance
-
-object RefFactory {
- private val factory = getGlobalStmInstance.getProgrammaticRefFactoryBuilder.build
-
- def createRef[T] = factory.atomicCreateRef[T]()
-
- def createRef[T](value: T) = factory.atomicCreateRef(value)
-}
+import org.multiverse.transactional.refs.BasicRef
/**
- * Ref.
+ * Ref
*
* @author Jonas Bonér
*/
object Ref {
- def apply[T]() = new Ref[T]
+ def apply[T]() = new Ref[T]()
def apply[T](initialValue: T) = new Ref[T](Some(initialValue))
@@ -33,77 +25,47 @@ object Ref {
}
/**
- * Implements a transactional managed reference.
+ * Transactional managed reference.
*
* @author Jonas Bonér
*/
-class Ref[T](initialOpt: Option[T] = None) extends Transactional {
+class Ref[T](initialOpt: Option[T] = None)
+ extends BasicRef[T](initialOpt.getOrElse(null.asInstanceOf[T]))
+ with Transactional {
+
self =>
def this() = this(None) // Java compatibility
- import org.multiverse.api.ThreadLocalTransaction._
-
val uuid = UUID.newUuid.toString
- private[this] val ref = {
- if (initialOpt.isDefined) RefFactory.createRef(initialOpt.get)
- else RefFactory.createRef[T]
- }
-
- def swap(elem: T) = {
- ensureIsInTransaction
- ref.set(elem)
- }
+ def swap(elem: T) = set(elem)
def alter(f: T => T): T = {
- ensureIsInTransaction
ensureNotNull
- ref.set(f(ref.get))
- ref.get
+ set(f(this.get))
+ this.get
}
- def get: Option[T] = {
- ensureIsInTransaction
- if (ref.isNull) None
- else Some(ref.get)
- }
+ def getOption: Option[T] = Option(this.get)
- def getOrWait: T = {
- ensureIsInTransaction
- ref.getOrAwait
- }
+ def getOrWait: T = getOrAwait
- def getOrElse(default: => T): T = {
- ensureIsInTransaction
- if (ref.isNull) default
- else ref.get
- }
+ def getOrElse(default: => T): T =
+ if (isNull) default else this.get
- def isDefined: Boolean = {
- ensureIsInTransaction
- !ref.isNull
- }
+ def isDefined: Boolean = !isNull
- def isEmpty: Boolean = {
- ensureIsInTransaction
- ref.isNull
- }
+ def isEmpty: Boolean = isNull
- def map[B](f: T => B): Ref[B] = {
- ensureIsInTransaction
- if (isEmpty) Ref[B] else Ref(f(ref.get))
- }
+ def map[B](f: T => B): Ref[B] =
+ if (isEmpty) Ref[B] else Ref(f(this.get))
- def flatMap[B](f: T => Ref[B]): Ref[B] = {
- ensureIsInTransaction
- if (isEmpty) Ref[B] else f(ref.get)
- }
+ def flatMap[B](f: T => Ref[B]): Ref[B] =
+ if (isEmpty) Ref[B] else f(this.get)
- def filter(p: T => Boolean): Ref[T] = {
- ensureIsInTransaction
- if (isDefined && p(ref.get)) Ref(ref.get) else Ref[T]
- }
+ def filter(p: T => Boolean): Ref[T] =
+ if (isDefined && p(this.get)) Ref(this.get) else Ref[T]
/**
* Necessary to keep from being implicitly converted to Iterable in for comprehensions.
@@ -117,34 +79,21 @@ class Ref[T](initialOpt: Option[T] = None) extends Transactional {
def withFilter(q: T => Boolean): WithFilter = new WithFilter(x => p(x) && q(x))
}
- def foreach[U](f: T => U): Unit = {
- ensureIsInTransaction
- if (isDefined) f(ref.get)
- }
+ def foreach[U](f: T => U): Unit =
+ if (isDefined) f(this.get)
- def elements: Iterator[T] = {
- ensureIsInTransaction
- if (isEmpty) Iterator.empty else Iterator(ref.get)
- }
+ def elements: Iterator[T] =
+ if (isEmpty) Iterator.empty else Iterator(this.get)
- def toList: List[T] = {
- ensureIsInTransaction
- if (isEmpty) List() else List(ref.get)
- }
+ def toList: List[T] =
+ if (isEmpty) List() else List(this.get)
- def toRight[X](left: => X) = {
- ensureIsInTransaction
- if (isEmpty) Left(left) else Right(ref.get)
- }
+ def toRight[X](left: => X) =
+ if (isEmpty) Left(left) else Right(this.get)
- def toLeft[X](right: => X) = {
- ensureIsInTransaction
- if (isEmpty) Right(right) else Left(ref.get)
- }
-
- private def ensureIsInTransaction =
- if (getThreadLocalTransaction eq null) throw new NoTransactionInScopeException
+ def toLeft[X](right: => X) =
+ if (isEmpty) Right(right) else Left(this.get)
private def ensureNotNull =
- if (ref.isNull) throw new RuntimeException("Cannot alter Ref's value when it is null")
+ if (isNull) throw new RuntimeException("Cannot alter Ref's value when it is null")
}
diff --git a/akka-core/src/main/scala/stm/Transaction.scala b/akka-core/src/main/scala/stm/Transaction.scala
index 54f20a3504..0951cbc5c5 100644
--- a/akka-core/src/main/scala/stm/Transaction.scala
+++ b/akka-core/src/main/scala/stm/Transaction.scala
@@ -83,11 +83,12 @@ object Transaction {
if (JTA_AWARE) Some(TransactionContainer())
else None
- log.trace("Creating %s", toString)
+ log.ifTrace("Creating transaction " + toString)
// --- public methods ---------
def begin = synchronized {
+ log.ifTrace("Starting transaction " + toString)
jta.foreach { txContainer =>
txContainer.begin
txContainer.registerSynchronization(new StmSynchronization(txContainer, this))
@@ -95,14 +96,14 @@ object Transaction {
}
def commit = synchronized {
- log.trace("Committing transaction %s", toString)
+ log.ifTrace("Committing transaction " + toString)
persistentStateMap.valuesIterator.foreach(_.commit)
status = TransactionStatus.Completed
jta.foreach(_.commit)
}
def abort = synchronized {
- log.trace("Aborting transaction %s", toString)
+ log.ifTrace("Aborting transaction " + toString)
jta.foreach(_.rollback)
persistentStateMap.valuesIterator.foreach(_.abort)
persistentStateMap.clear
diff --git a/akka-core/src/main/scala/stm/TransactionFactory.scala b/akka-core/src/main/scala/stm/TransactionFactory.scala
index 56982bb759..691fec675b 100644
--- a/akka-core/src/main/scala/stm/TransactionFactory.scala
+++ b/akka-core/src/main/scala/stm/TransactionFactory.scala
@@ -22,8 +22,7 @@ object TransactionConfig {
val FAMILY_NAME = "DefaultTransaction"
val READONLY = null.asInstanceOf[JBoolean]
val MAX_RETRIES = config.getInt("akka.stm.max-retries", 1000)
- val TIMEOUT = config.getLong("akka.stm.timeout", Long.MaxValue)
- val TIME_UNIT = config.getString("akka.stm.time-unit", "seconds")
+ val TIMEOUT = config.getLong("akka.stm.timeout", 10)
val TRACK_READS = null.asInstanceOf[JBoolean]
val WRITE_SKEW = config.getBool("akka.stm.write-skew", true)
val EXPLICIT_RETRIES = config.getBool("akka.stm.explicit-retries", false)
@@ -37,8 +36,8 @@ object TransactionConfig {
def traceLevel(level: String) = level.toLowerCase match {
case "coarse" | "course" => Transaction.TraceLevel.Coarse
- case "fine" => Transaction.TraceLevel.Fine
- case _ => Transaction.TraceLevel.None
+ case "fine" => Transaction.TraceLevel.Fine
+ case _ => Transaction.TraceLevel.None
}
/**
@@ -125,8 +124,9 @@ object TransactionFactory {
quickRelease: Boolean = TransactionConfig.QUICK_RELEASE,
traceLevel: TraceLevel = TransactionConfig.TRACE_LEVEL,
hooks: Boolean = TransactionConfig.HOOKS) = {
- val config = new TransactionConfig(familyName, readonly, maxRetries, timeout, trackReads, writeSkew,
- explicitRetries, interruptible, speculative, quickRelease, traceLevel, hooks)
+ val config = new TransactionConfig(
+ familyName, readonly, maxRetries, timeout, trackReads, writeSkew,
+ explicitRetries, interruptible, speculative, quickRelease, traceLevel, hooks)
new TransactionFactory(config)
}
}
@@ -152,8 +152,9 @@ object TransactionFactory {
*
* @see TransactionConfig for configuration options.
*/
-class TransactionFactory(val config: TransactionConfig = DefaultTransactionConfig, defaultName: String = TransactionConfig.FAMILY_NAME) {
- self =>
+class TransactionFactory(
+ val config: TransactionConfig = DefaultTransactionConfig,
+ defaultName: String = TransactionConfig.FAMILY_NAME) { self =>
// use the config family name if it's been set, otherwise defaultName - used by actors to set class name as default
val familyName = if (config.familyName != TransactionConfig.FAMILY_NAME) config.familyName else defaultName
diff --git a/akka-core/src/main/scala/stm/TransactionManagement.scala b/akka-core/src/main/scala/stm/TransactionManagement.scala
index 0c6a244f42..65f8d7624c 100644
--- a/akka-core/src/main/scala/stm/TransactionManagement.scala
+++ b/akka-core/src/main/scala/stm/TransactionManagement.scala
@@ -7,6 +7,7 @@ package se.scalablesolutions.akka.stm
import se.scalablesolutions.akka.util.Logging
import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.TimeUnit
import org.multiverse.api.{StmUtils => MultiverseStmUtils}
import org.multiverse.api.ThreadLocalTransaction._
@@ -14,16 +15,20 @@ import org.multiverse.api.{Transaction => MultiverseTransaction}
import org.multiverse.commitbarriers.CountDownCommitBarrier
import org.multiverse.templates.{TransactionalCallable, OrElseTemplate}
-class StmException(msg: String) extends RuntimeException(msg)
+class TransactionSetAbortedException(msg: String) extends RuntimeException(msg)
+// TODO Should we remove TransactionAwareWrapperException? Not used anywhere yet.
class TransactionAwareWrapperException(val cause: Throwable, val tx: Option[Transaction]) extends RuntimeException(cause) {
override def toString = "TransactionAwareWrapperException[" + cause + ", " + tx + "]"
}
+/**
+ * Internal helper methods and properties for transaction management.
+ */
object TransactionManagement extends TransactionManagement {
import se.scalablesolutions.akka.config.Config._
- // move to stm.global.fair?
+ // FIXME move to stm.global.fair?
val FAIR_TRANSACTIONS = config.getBool("akka.stm.fair", true)
private[akka] val transactionSet = new ThreadLocal[Option[CountDownCommitBarrier]]() {
@@ -47,6 +52,9 @@ object TransactionManagement extends TransactionManagement {
}
}
+/**
+ * Internal helper methods for transaction management.
+ */
trait TransactionManagement {
private[akka] def createNewTransactionSet: CountDownCommitBarrier = {
@@ -111,7 +119,9 @@ class LocalStm extends TransactionManagement with Logging {
factory.boilerplate.execute(new TransactionalCallable[T]() {
def call(mtx: MultiverseTransaction): T = {
factory.addHooks
- body
+ val result = body
+ log.ifTrace("Committing local transaction [" + mtx + "]")
+ result
}
})
}
@@ -145,10 +155,14 @@ class GlobalStm extends TransactionManagement with Logging {
factory.addHooks
val result = body
val txSet = getTransactionSetInScope
- log.trace("Committing transaction [%s]\n\tby joining transaction set [%s]", mtx, txSet)
- // FIXME ? txSet.tryJoinCommit(mtx, TransactionManagement.TRANSACTION_TIMEOUT, TimeUnit.MILLISECONDS)
- try { txSet.joinCommit(mtx) } catch { case e: IllegalStateException => {} }
- clearTransaction
+ log.ifTrace("Committing global transaction [" + mtx + "]\n\tand joining transaction set [" + txSet + "]")
+ try {
+ txSet.tryJoinCommit(
+ mtx,
+ TransactionConfig.DefaultTimeout.length,
+ TransactionConfig.DefaultTimeout.unit)
+ // Need to catch IllegalStateException until we have fix in Multiverse, since it throws it by mistake
+ } catch { case e: IllegalStateException => {} }
result
}
})
@@ -156,18 +170,19 @@ class GlobalStm extends TransactionManagement with Logging {
}
trait StmUtil {
+
/**
* Schedule a deferred task on the thread local transaction (use within an atomic).
* This is executed when the transaction commits.
*/
- def deferred[T](body: => T): Unit =
+ def deferred[T](body: => T): Unit =
MultiverseStmUtils.scheduleDeferredTask(new Runnable { def run = body })
/**
* Schedule a compensating task on the thread local transaction (use within an atomic).
* This is executed when the transaction aborts.
*/
- def compensating[T](body: => T): Unit =
+ def compensating[T](body: => T): Unit =
MultiverseStmUtils.scheduleCompensatingTask(new Runnable { def run = body })
/**
@@ -178,6 +193,14 @@ trait StmUtil {
/**
* Use either-orElse to combine two blocking transactions.
+ * Usage:
+ *