diff --git a/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala b/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala
index 2eacad344b..0e4432159a 100644
--- a/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala
+++ b/akka-actor/src/main/scala/akka/cluster/ClusterInterface.scala
@@ -465,13 +465,22 @@ trait ClusterNode {
*/
def send(f: Function1[Any, Any], arg: Any, replicationFactor: Int): List[Future[Any]]
+ /**
+ * Stores a configuration element under a specific key.
+ * If the key already exists then it will be overwritten.
+ */
def setConfigElement(key: String, bytes: Array[Byte])
/**
* Returns the config element for the key or NULL if no element exists under the key.
+ * Returns Some(element) if it exists else None
*/
def getConfigElement(key: String): Option[Array[Byte]]
+ /**
+ * Removes configuration element for a specific key.
+ * Does nothing if the key does not exist.
+ */
def removeConfigElement(key: String)
def getConfigElementKeys: Array[String]
diff --git a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala
index 2d91fc2345..d0e21c3dd4 100644
--- a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala
+++ b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala
@@ -1143,6 +1143,10 @@ class DefaultClusterNode private[akka] (
// Config
// =======================================
+ /**
+ * Stores a configuration element under a specific key.
+ * If the key already exists then it will be overwritten.
+ */
def setConfigElement(key: String, bytes: Array[Byte]) {
val compressedBytes = if (shouldCompressData) LZF.compress(bytes) else bytes
EventHandler.debug(this,
@@ -1168,6 +1172,7 @@ class DefaultClusterNode private[akka] (
/**
* Returns the config element for the key or NULL if no element exists under the key.
+ * Returns Some(element) if it exists else None
*/
def getConfigElement(key: String): Option[Array[Byte]] = try {
Some(zkClient.connection.readData(configurationPathFor(key), new Stat, true))
@@ -1175,6 +1180,10 @@ class DefaultClusterNode private[akka] (
case e: KeeperException.NoNodeException ⇒ None
}
+ /**
+ * Removes configuration element for a specific key.
+ * Does nothing if the key does not exist.
+ */
def removeConfigElement(key: String) {
ignore[ZkNoNodeException] {
EventHandler.debug(this,
diff --git a/akka-cluster/src/test/scala/akka/cluster/ClusterSpec.scala b/akka-cluster/src/test/scala/akka/cluster/ClusterSpec.scala
index 1d3b8b8df1..1af789d666 100644
--- a/akka-cluster/src/test/scala/akka/cluster/ClusterSpec.scala
+++ b/akka-cluster/src/test/scala/akka/cluster/ClusterSpec.scala
@@ -305,38 +305,6 @@ class ClusterSpec extends WordSpec with MustMatchers with BeforeAndAfterAll with
node2.stop
}
- "be able to set and get config elements" in {
- val node1 = Cluster.newNode(nodeAddress = NodeAddress("test-cluster", "set-get-config-1", port = 9001))
- val node2 = Cluster.newNode(nodeAddress = NodeAddress("test-cluster", "set-get-config-2", port = 9002))
- node1.start
- node2.start
-
- node1.setConfigElement("key1", "value1".getBytes)
- node2.getConfigElement("key1") must be("value1".getBytes)
-
- node2.setConfigElement("key2", "value2".getBytes)
- node1.getConfigElement("key2") must be("value2".getBytes)
-
- node1.stop
- node2.stop
- }
-
- "be able to remove config elements" in {
- val node1 = Cluster.newNode(nodeAddress = NodeAddress("test-cluster", "remove-config-1", port = 9001))
- val node2 = Cluster.newNode(nodeAddress = NodeAddress("test-cluster", "remove-config-2", port = 9002))
- node1.start
- node2.start
-
- node1.setConfigElement("key1", "value1".getBytes)
- node2.getConfigElement("key1") must be("value1".getBytes)
-
- node2.removeConfigElement("key1")
- node1.getConfigElement("key1") must be(null)
-
- node1.stop
- node2.stop
- }
-
"be able to replicate an actor" in {
// create actor
val actorRef = actorOf[MyJavaSerializableActor]("actor-address").start
diff --git a/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode1.conf b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode1.conf
new file mode 100644
index 0000000000..480c30c09d
--- /dev/null
+++ b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode1.conf
@@ -0,0 +1 @@
+akka.event-handler-level = "DEBUG"
diff --git a/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode1.opts b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode1.opts
new file mode 100644
index 0000000000..a88c260d8c
--- /dev/null
+++ b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode1.opts
@@ -0,0 +1 @@
+-Dakka.cluster.nodename=node1 -Dakka.cluster.port=9991
diff --git a/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode2.conf b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode2.conf
new file mode 100644
index 0000000000..480c30c09d
--- /dev/null
+++ b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode2.conf
@@ -0,0 +1 @@
+akka.event-handler-level = "DEBUG"
diff --git a/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode2.opts b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode2.opts
new file mode 100644
index 0000000000..f1e01f253d
--- /dev/null
+++ b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmNode2.opts
@@ -0,0 +1 @@
+-Dakka.cluster.nodename=node2 -Dakka.cluster.port=9992
diff --git a/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmSpec.scala b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmSpec.scala
new file mode 100644
index 0000000000..0d9da9196c
--- /dev/null
+++ b/akka-cluster/src/test/scala/akka/cluster/configuration/ConfigurationStorageMultiJvmSpec.scala
@@ -0,0 +1,100 @@
+/**
+ * Copyright (C) 2009-2011 Scalable Solutions AB
+ */
+
+package akka.cluster.configuration
+
+import org.scalatest.WordSpec
+import org.scalatest.matchers.MustMatchers
+import org.scalatest.BeforeAndAfterAll
+
+import akka.cluster._
+import Cluster._
+
+object ConfigurationStorageMultiJvmSpec {
+ var NrOfNodes = 2
+}
+
+class ConfigurationStorageMultiJvmNode1 extends WordSpec with MustMatchers with BeforeAndAfterAll {
+ import ConfigurationStorageMultiJvmSpec._
+
+ "A cluster" must {
+
+ "be able to store, read and remove custom configuration data" in {
+
+ barrier("start-node-1", NrOfNodes) {
+ node.start()
+ }
+
+ barrier("start-node-2", NrOfNodes) {
+ }
+
+ barrier("store-config-data-node-1", NrOfNodes) {
+ node.setConfigElement("key1", "value1".getBytes)
+ }
+
+ barrier("read-config-data-node-2", NrOfNodes) {
+ }
+
+ barrier("remove-config-data-node-2", NrOfNodes) {
+ }
+
+ barrier("try-read-config-data-node-1", NrOfNodes) {
+ val option = node.getConfigElement("key1")
+ option.isDefined must be(false)
+
+ val elements = node.getConfigElementKeys
+ elements.size must be(0)
+ }
+
+ node.shutdown()
+ }
+ }
+
+ override def beforeAll() = {
+ startLocalCluster()
+ }
+
+ override def afterAll() = {
+ shutdownLocalCluster()
+ }
+}
+
+class ConfigurationStorageMultiJvmNode2 extends WordSpec with MustMatchers {
+ import ConfigurationStorageMultiJvmSpec._
+
+ "A cluster" must {
+
+ "be able to store, read and remove custom configuration data" in {
+
+ barrier("start-node-1", NrOfNodes) {
+ }
+
+ barrier("start-node-2", NrOfNodes) {
+ node.start()
+ }
+
+ barrier("store-config-data-node-1", NrOfNodes) {
+ }
+
+ barrier("read-config-data-node-2", NrOfNodes) {
+ val option = node.getConfigElement("key1")
+ option.isDefined must be(true)
+ option.get must be("value1".getBytes)
+
+ val elements = node.getConfigElementKeys
+ elements.size must be(1)
+ elements.head must be("key1")
+ }
+
+ barrier("remove-config-data-node-2", NrOfNodes) {
+ node.removeConfigElement("key1")
+ }
+
+ barrier("try-read-config-data-node-1", NrOfNodes) {
+ }
+
+ node.shutdown()
+ }
+ }
+}