diff --git a/.idea/misc.xml b/.idea/misc.xml
index 71286c2..216536e 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 6e30e28..f29110e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -20,6 +20,7 @@ group = "it.norangeb.unisannio"
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5")
+ implementation("org.apache.activemq:activemq-client:5.15.12")
testCompile("junit", "junit", "4.12")
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.7.0-beta2")
}
diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml
index 4e9cc28..8a9ad40 100644
--- a/config/detekt/detekt.yml
+++ b/config/detekt/detekt.yml
@@ -501,7 +501,7 @@ style:
active: true
maxJumpCount: 1
MagicNumber:
- active: true
+ active: false
excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
ignoreNumbers: '-1,0,1,2,3,42,100,500,1000,4242'
ignoreHashCodeFunction: true
diff --git a/src/main/kotlin/drills/drill06/exercise1/point1/Receiver.kt b/src/main/kotlin/drills/drill06/exercise1/point1/Receiver.kt
new file mode 100644
index 0000000..aa34348
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point1/Receiver.kt
@@ -0,0 +1,28 @@
+package drills.drill06.exercise1.point1
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.QueueConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: QueueConnectionFactory = ActiveMQConnectionFactory(url)
+
+ val connection = factory.createQueueConnection()
+ connection.start()
+
+ val session = connection.createQueueSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val queue = session.createQueue("hello")
+ val receiver = session.createReceiver(queue)
+
+ val msg = receiver.receive()
+ println((msg as TextMessage).text)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point1/Sender.kt b/src/main/kotlin/drills/drill06/exercise1/point1/Sender.kt
new file mode 100644
index 0000000..2ba7461
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point1/Sender.kt
@@ -0,0 +1,25 @@
+package drills.drill06.exercise1.point1
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.QueueConnectionFactory
+import javax.jms.Session
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: QueueConnectionFactory = ActiveMQConnectionFactory(url)
+ val connection = factory.createQueueConnection()
+
+ val session = connection.createQueueSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val queue = session.createQueue("hello")
+ val sender = session.createSender(queue)
+
+ val msg = session.createTextMessage("Hello Home!")
+ sender.send(msg)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point2/Receiver.kt b/src/main/kotlin/drills/drill06/exercise1/point2/Receiver.kt
new file mode 100644
index 0000000..33907c5
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point2/Receiver.kt
@@ -0,0 +1,28 @@
+package drills.drill06.exercise1.point2
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.QueueConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: QueueConnectionFactory = ActiveMQConnectionFactory(url)
+
+ val connection = factory.createQueueConnection()
+ connection.start()
+
+ val session = connection.createQueueSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val queue = session.createQueue("hello")
+ val receiver = session.createReceiver(queue)
+
+ receiver.setMessageListener {
+ println((it as TextMessage).text)
+ session.close()
+ connection.close()
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point2/Sender.kt b/src/main/kotlin/drills/drill06/exercise1/point2/Sender.kt
new file mode 100644
index 0000000..b3f2d45
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point2/Sender.kt
@@ -0,0 +1,25 @@
+package drills.drill06.exercise1.point2
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.QueueConnectionFactory
+import javax.jms.Session
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: QueueConnectionFactory = ActiveMQConnectionFactory(url)
+ val connection = factory.createQueueConnection()
+
+ val session = connection.createQueueSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val queue = session.createQueue("hello")
+ val sender = session.createSender(queue)
+
+ val msg = session.createTextMessage("Hello Home!")
+ sender.send(msg)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point3/Publisher.kt b/src/main/kotlin/drills/drill06/exercise1/point3/Publisher.kt
new file mode 100644
index 0000000..4149d37
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point3/Publisher.kt
@@ -0,0 +1,25 @@
+package drills.drill06.exercise1.point3
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(url)
+ val connection = factory.createTopicConnection()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic("hello")
+ val publisher = session.createPublisher(topic)
+
+ val msg = session.createTextMessage("Hello Home!")
+ publisher.publish(msg)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point3/Subscriber.kt b/src/main/kotlin/drills/drill06/exercise1/point3/Subscriber.kt
new file mode 100644
index 0000000..47075d2
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point3/Subscriber.kt
@@ -0,0 +1,28 @@
+package drills.drill06.exercise1.point3
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(url)
+
+ val connection = factory.createTopicConnection()
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic("hello")
+ val subscriber = session.createSubscriber(topic)
+
+ val msg = subscriber.receive()
+ println((msg as TextMessage).text)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point4/Publisher.kt b/src/main/kotlin/drills/drill06/exercise1/point4/Publisher.kt
new file mode 100644
index 0000000..0e0f101
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point4/Publisher.kt
@@ -0,0 +1,25 @@
+package drills.drill06.exercise1.point4
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(url)
+ val connection = factory.createTopicConnection()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic("hello")
+ val publisher = session.createPublisher(topic)
+
+ val msg = session.createTextMessage("Hello Home!")
+ publisher.publish(msg)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point4/Subscriber.kt b/src/main/kotlin/drills/drill06/exercise1/point4/Subscriber.kt
new file mode 100644
index 0000000..f766e5f
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point4/Subscriber.kt
@@ -0,0 +1,28 @@
+package drills.drill06.exercise1.point4
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(url)
+
+ val connection = factory.createTopicConnection()
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic("hello")
+ val subscriber = session.createSubscriber(topic)
+
+ subscriber.setMessageListener {
+ println((it as TextMessage).text)
+ session.close()
+ connection.close()
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point5/Publisher.kt b/src/main/kotlin/drills/drill06/exercise1/point5/Publisher.kt
new file mode 100644
index 0000000..4a6a99f
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point5/Publisher.kt
@@ -0,0 +1,25 @@
+package drills.drill06.exercise1.point5
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(url)
+ val connection = factory.createTopicConnection()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic("hello")
+ val publisher = session.createPublisher(topic)
+
+ val msg = session.createTextMessage("Hello Home!")
+ publisher.publish(msg)
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise1/point5/Subscriber.kt b/src/main/kotlin/drills/drill06/exercise1/point5/Subscriber.kt
new file mode 100644
index 0000000..3263c79
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise1/point5/Subscriber.kt
@@ -0,0 +1,29 @@
+package drills.drill06.exercise1.point5
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val url = "tcp://localhost:61616"
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(url)
+
+ val connection = factory.createTopicConnection()
+ connection.clientID = "client1"
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic("hello")
+ val subscriber = session.createDurableSubscriber(topic, "s1")
+
+ subscriber.setMessageListener {
+ println((it as TextMessage).text)
+ session.close()
+ connection.close()
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise2/ChatClient.kt b/src/main/kotlin/drills/drill06/exercise2/ChatClient.kt
new file mode 100644
index 0000000..6a70d17
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise2/ChatClient.kt
@@ -0,0 +1,38 @@
+package drills.drill06.exercise2
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory()
+
+ val connection = factory.createTopicConnection()
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+ val room = session.createTopic("movies")
+
+ val publisher = session.createPublisher(room)
+ val subscriber = session.createSubscriber(room)
+
+ subscriber.setMessageListener {
+ println("peer: ${(it as TextMessage).text}")
+ }
+
+ var line = readLine()
+ val msg = session.createTextMessage()
+
+ while (line != ".") {
+ msg.text = line
+ publisher.publish(msg)
+ line = readLine()
+ }
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise3/ChatClient.kt b/src/main/kotlin/drills/drill06/exercise3/ChatClient.kt
new file mode 100644
index 0000000..9b8f463
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise3/ChatClient.kt
@@ -0,0 +1,41 @@
+package drills.drill06.exercise3
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TextMessage
+import javax.jms.TopicConnectionFactory
+
+fun main() {
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory()
+
+ val connection = factory.createTopicConnection()
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+ val room = session.createTopic("movies")
+
+ val publisher = session.createPublisher(room)
+
+ val selector = "Subtopic = 'Dark Comedy'"
+ val subscriber = session.createSubscriber(room, selector, true)
+
+ subscriber.setMessageListener {
+ println("peer: ${(it as TextMessage).text}")
+ }
+
+ var line = readLine()
+ val msg = session.createTextMessage()
+
+ while (line != ".") {
+ msg.text = line
+ msg.setStringProperty("Subtopic", "Dark Comedy")
+ publisher.publish(msg)
+ line = readLine()
+ }
+
+ session.close()
+ connection.close()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/SensorNet.kt b/src/main/kotlin/drills/drill06/exercise4/SensorNet.kt
new file mode 100644
index 0000000..d421fbe
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/SensorNet.kt
@@ -0,0 +1,7 @@
+package drills.drill06.exercise4
+
+object SensorNet {
+ const val TOPIC = "sensorNet"
+ const val URI = "tcp://localhost:61616"
+ const val PROPERTY = "temperature"
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/actuator/Action.kt b/src/main/kotlin/drills/drill06/exercise4/actuator/Action.kt
new file mode 100644
index 0000000..7a4e58e
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/actuator/Action.kt
@@ -0,0 +1,28 @@
+package drills.drill06.exercise4.actuator
+
+interface Action {
+ enum class State {
+ ON, OFF
+ }
+
+ fun getActionName(): String
+ fun getState(): State
+ fun on()
+ fun off()
+}
+
+abstract class VirtualAction : Action {
+ private var state = Action.State.OFF
+
+ override fun getState(): Action.State = state
+
+ override fun off() {
+ println("Switching off: ${getActionName()}")
+ state = Action.State.OFF
+ }
+
+ override fun on() {
+ println("Switching on: ${getActionName()}")
+ state = Action.State.ON
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/actuator/Actuator.kt b/src/main/kotlin/drills/drill06/exercise4/actuator/Actuator.kt
new file mode 100644
index 0000000..61dd914
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/actuator/Actuator.kt
@@ -0,0 +1,33 @@
+package drills.drill06.exercise4.actuator
+
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+class Actuator(private val action: Action) : Thread() {
+ var latch = CountDownLatch(1)
+
+ override fun run() {
+ while (true) {
+ latch.await()
+
+ synchronized(this) {
+ latch = CountDownLatch(1)
+ }
+
+ if (action.getState() == Action.State.OFF)
+ action.on()
+
+ latch.await(2050, TimeUnit.MILLISECONDS)
+
+ synchronized(this) {
+ if (latch.count == 1L)
+ action.off()
+ }
+ }
+ }
+
+ @Synchronized
+ fun actuate() {
+ latch.countDown()
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/actuator/AntiFrostNode.kt b/src/main/kotlin/drills/drill06/exercise4/actuator/AntiFrostNode.kt
new file mode 100644
index 0000000..45744be
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/actuator/AntiFrostNode.kt
@@ -0,0 +1,12 @@
+package drills.drill06.exercise4.actuator
+
+import drills.drill06.exercise4.SensorNet
+
+fun main() {
+ TemperatureActuatorNode(
+ SensorNet.URI,
+ "anti-frost",
+ SensorNet.TOPIC,
+ "<= 4"
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/actuator/IrrigationNode.kt b/src/main/kotlin/drills/drill06/exercise4/actuator/IrrigationNode.kt
new file mode 100644
index 0000000..5fc869b
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/actuator/IrrigationNode.kt
@@ -0,0 +1,12 @@
+package drills.drill06.exercise4.actuator
+
+import drills.drill06.exercise4.SensorNet
+
+fun main() {
+ TemperatureActuatorNode(
+ SensorNet.URI,
+ "irrigation",
+ SensorNet.TOPIC,
+ ">= 20"
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/actuator/TemperatureActuatorNode.kt b/src/main/kotlin/drills/drill06/exercise4/actuator/TemperatureActuatorNode.kt
new file mode 100644
index 0000000..9680404
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/actuator/TemperatureActuatorNode.kt
@@ -0,0 +1,44 @@
+package drills.drill06.exercise4.actuator
+
+import drills.drill06.exercise4.SensorNet
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TopicConnectionFactory
+
+class TemperatureActuatorNode(
+ private val uri: String,
+ private val name: String,
+ private val topicName: String,
+ private val selector: String
+) {
+ private val actuator = Actuator(object : VirtualAction() {
+ override fun getActionName(): String = name
+ })
+
+ init {
+ actuator.start()
+ }
+
+ fun start() {
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(uri)
+ val connection = factory.createTopicConnection()
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic(topicName)
+ val subscriber = session.createSubscriber(
+ topic,
+ "${SensorNet.PROPERTY} $selector",
+ false
+ )
+
+ subscriber.setMessageListener {
+ println("$name: ${it.getDoubleProperty("temperature")}")
+ actuator.actuate()
+ }
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/sensor/Sampler.kt b/src/main/kotlin/drills/drill06/exercise4/sensor/Sampler.kt
new file mode 100644
index 0000000..5840d06
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/sensor/Sampler.kt
@@ -0,0 +1,21 @@
+package drills.drill06.exercise4.sensor
+
+import kotlin.random.Random
+
+interface Sampler {
+ fun getSample(): T
+}
+
+class SampleGenerator(seed: Int = 0) : Sampler {
+ private val samples = listOf(
+ 6, 4, 3, 2, 4, 10, 18, 20, 22, 24, 20, 15, 10, 7
+ )
+
+ private val random = Random(seed)
+
+ private var i = 0
+
+ override fun getSample(): Double {
+ return samples[i++ % samples.size].toDouble() + random.nextDouble(-1.5, 1.5)
+ }
+}
diff --git a/src/main/kotlin/drills/drill06/exercise4/sensor/TemperatureSensorNode.kt b/src/main/kotlin/drills/drill06/exercise4/sensor/TemperatureSensorNode.kt
new file mode 100644
index 0000000..6075205
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise4/sensor/TemperatureSensorNode.kt
@@ -0,0 +1,44 @@
+package drills.drill06.exercise4.sensor
+
+import drills.drill06.exercise4.SensorNet
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TopicConnectionFactory
+
+class TemperatureSensorNode(val id: Int, val uri: String, val topicName: String) {
+ private val sampler: Sampler =
+ SampleGenerator(id)
+
+ fun start() {
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(uri)
+ val connection = factory.createTopicConnection()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topic = session.createTopic(topicName)
+ val publisher = session.createPublisher(topic)
+
+ val msg = session.createMessage()
+
+ while (true) {
+ val sample = sampler.getSample()
+ msg.setDoubleProperty(SensorNet.PROPERTY, sample)
+ publisher.publish(msg)
+
+ println("Sensor-$id: $sample")
+
+ Thread.sleep(2000)
+ }
+ }
+}
+
+fun main() {
+ TemperatureSensorNode(
+ 0,
+ SensorNet.URI,
+ SensorNet.TOPIC
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/SensorNet.kt b/src/main/kotlin/drills/drill06/exercise5/SensorNet.kt
new file mode 100644
index 0000000..c7d2010
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/SensorNet.kt
@@ -0,0 +1,8 @@
+package drills.drill06.exercise5
+
+object SensorNet {
+ const val TOPIC_SENSOR = "sensor"
+ const val TOPIC_ACTUATOR = "actuator"
+ const val URI = "tcp://localhost:61616"
+ const val PROPERTY = "temperature"
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/actuator/AntiFrostNode.kt b/src/main/kotlin/drills/drill06/exercise5/actuator/AntiFrostNode.kt
new file mode 100644
index 0000000..1544c37
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/actuator/AntiFrostNode.kt
@@ -0,0 +1,13 @@
+package drills.drill06.exercise5.actuator
+
+import drills.drill06.exercise4.actuator.TemperatureActuatorNode
+import drills.drill06.exercise5.SensorNet
+
+fun main() {
+ TemperatureActuatorNode(
+ SensorNet.URI,
+ "anti-frost",
+ SensorNet.TOPIC_ACTUATOR,
+ "<= 4"
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/actuator/IrrigationNode.kt b/src/main/kotlin/drills/drill06/exercise5/actuator/IrrigationNode.kt
new file mode 100644
index 0000000..a421214
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/actuator/IrrigationNode.kt
@@ -0,0 +1,13 @@
+package drills.drill06.exercise5.actuator
+
+import drills.drill06.exercise4.actuator.TemperatureActuatorNode
+import drills.drill06.exercise5.SensorNet
+
+fun main() {
+ TemperatureActuatorNode(
+ SensorNet.URI,
+ "irrigation",
+ SensorNet.TOPIC_ACTUATOR,
+ ">= 20"
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/middleware/MeanNode.kt b/src/main/kotlin/drills/drill06/exercise5/middleware/MeanNode.kt
new file mode 100644
index 0000000..bfd92a2
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/middleware/MeanNode.kt
@@ -0,0 +1,62 @@
+package drills.drill06.exercise5.middleware
+
+import drills.drill06.exercise5.SensorNet
+import org.apache.activemq.ActiveMQConnectionFactory
+import javax.jms.Session
+import javax.jms.TopicConnectionFactory
+
+class MeanNode(
+ private val uri: String,
+ private val topicNameSensor: String,
+ private val topicNameActuator: String
+) {
+ fun start() {
+ val factory: TopicConnectionFactory = ActiveMQConnectionFactory(uri)
+ val connection = factory.createTopicConnection()
+ connection.start()
+
+ val session = connection.createTopicSession(
+ false,
+ Session.AUTO_ACKNOWLEDGE
+ )
+
+ val topicSensor = session.createTopic(topicNameSensor)
+ val topicActuator = session.createTopic(topicNameActuator)
+
+ val subscriber = session.createSubscriber(topicSensor)
+ val publisher = session.createPublisher(topicActuator)
+
+ val samples = mutableListOf()
+ val msg = session.createMessage()
+
+ while (true) {
+ val receiveMsg = subscriber.receiveNoWait()
+
+ if (receiveMsg != null) {
+ val sample = receiveMsg.getDoubleProperty("temperature")
+ samples.add(sample)
+ println("sample: $sample")
+ continue
+ }
+
+ if (samples.isNotEmpty()) {
+ val mean = samples.sum() / samples.size
+ samples.clear()
+ msg.setDoubleProperty("temperature", mean)
+ publisher.publish(msg)
+ println("MEAN: $mean")
+ println("-------------------------")
+ }
+
+ Thread.sleep(2000)
+ }
+ }
+}
+
+fun main() {
+ MeanNode(
+ SensorNet.URI,
+ SensorNet.TOPIC_SENSOR,
+ SensorNet.TOPIC_ACTUATOR
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor0.kt b/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor0.kt
new file mode 100644
index 0000000..38e4c6d
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor0.kt
@@ -0,0 +1,12 @@
+package drills.drill06.exercise5.sensor
+
+import drills.drill06.exercise4.sensor.TemperatureSensorNode
+import drills.drill06.exercise5.SensorNet
+
+fun main() {
+ TemperatureSensorNode(
+ 0,
+ SensorNet.URI,
+ SensorNet.TOPIC_SENSOR
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor1.kt b/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor1.kt
new file mode 100644
index 0000000..2e34979
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor1.kt
@@ -0,0 +1,12 @@
+package drills.drill06.exercise5.sensor
+
+import drills.drill06.exercise4.sensor.TemperatureSensorNode
+import drills.drill06.exercise5.SensorNet
+
+fun main() {
+ TemperatureSensorNode(
+ 1,
+ SensorNet.URI,
+ SensorNet.TOPIC_SENSOR
+ ).start()
+}
diff --git a/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor2.kt b/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor2.kt
new file mode 100644
index 0000000..08e1016
--- /dev/null
+++ b/src/main/kotlin/drills/drill06/exercise5/sensor/Sensor2.kt
@@ -0,0 +1,12 @@
+package drills.drill06.exercise5.sensor
+
+import drills.drill06.exercise4.sensor.TemperatureSensorNode
+import drills.drill06.exercise5.SensorNet
+
+fun main() {
+ TemperatureSensorNode(
+ 2,
+ SensorNet.URI,
+ SensorNet.TOPIC_SENSOR
+ ).start()
+}