From 6b021f335c9742994c7b3b012236d0035d251f63 Mon Sep 17 00:00:00 2001 From: Christoph Stahl Date: Thu, 9 May 2024 18:24:41 +0200 Subject: [PATCH] Blatt 04 --- README.md | 41 +++++++++ src/main/java/com/example/AkkaMainSystem.java | 59 ++++++++++--- src/main/java/com/example/AkkaStart.java | 2 +- src/main/java/com/example/ExampleActor.java | 35 -------- .../java/com/example/ExampleTimerActor.java | 45 ---------- src/main/java/com/example/TimerActor.java | 87 +++++++++++++++++++ 6 files changed, 174 insertions(+), 95 deletions(-) create mode 100644 README.md delete mode 100644 src/main/java/com/example/ExampleActor.java delete mode 100644 src/main/java/com/example/ExampleTimerActor.java create mode 100644 src/main/java/com/example/TimerActor.java diff --git a/README.md b/README.md new file mode 100644 index 0000000..459c4f6 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Blatt 04 - Timed Messages + +In diesem Blatt ging es allen voran, um die möglichkeit Zeitgesteuert Nachrichten zu senden. Möglich macht es der +`TimerScheduler`. + +Damit ein Aktor zugriff auf einen `TimerScheduler` hat, muss der Aktor damit erstellt werden. Anstelle dem _regulärem_ + +```java +public static Behavior create(... arguments ...) { + return Behaviors.setup(context -> new Actor(context, ... arguments ...)); +} +``` + +muss ein Aktor nun mit `Timers` erstellt werden. + +```java +public static Behavior create(... arguments ...) { + return Behaviors.setup(context -> Behaviors.withTimers(timers -> new Actor(context, timers, ... arguments ...))); +} +``` + +Entsprechend muss im Konstruktor dann auch an der entsprechenden Stelle ein `TimerScheduler` erwartet werden. + +```java +private Actor(ActorContext context, TimerScheduler timers, ... arguments ...) { + super(context); + this.timers = timers; // wir speichern uns einfach den TimerScheduler + // restliche argumente setzen +} +``` + +Nun kann der `TimerScheduler` genutzt werden. Grundsätzlich wird mit dem `TimerScheduler` eine Nachricht nach einer +bestimmten Zeit **an sich selbst** gesendet. Diese muss (wie jede Nachricht) dann auch behandelt werden. + +Der Code +```java +this.timers.startSingleTimer(new Message(), Duration.ofSeconds(10)); +``` +sendet eine Nachricht (`Message`) nach 10 Sekunden an sich selbst. + +`TimerScheduler` können noch mehr, aber das ist erstmal alles, was zum Verständnis der Aufgabe gebraucht wird. diff --git a/src/main/java/com/example/AkkaMainSystem.java b/src/main/java/com/example/AkkaMainSystem.java index 868351b..fae59a6 100644 --- a/src/main/java/com/example/AkkaMainSystem.java +++ b/src/main/java/com/example/AkkaMainSystem.java @@ -4,31 +4,62 @@ import akka.actor.typed.ActorRef; import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.*; -public class AkkaMainSystem extends AbstractBehavior { +import java.time.Duration; +import java.util.ArrayList; - public static class Create { +public class AkkaMainSystem extends AbstractBehavior { + + + + public interface Message { } + public static class Create implements Message { } + public static class Terminate implements Message { } + + public static Behavior create() { + return Behaviors.setup(context -> Behaviors.withTimers(timers -> new AkkaMainSystem(context, timers))); } - public static Behavior create() { - return Behaviors.setup(AkkaMainSystem::new); - } + private final TimerScheduler timers; + private ArrayList> all_actors; - private AkkaMainSystem(ActorContext context) { + private AkkaMainSystem(ActorContext context, TimerScheduler timers) { super(context); + this.timers = timers; } @Override - public Receive createReceive() { - return newReceiveBuilder().onMessage(Create.class, this::onCreate).build(); + public Receive createReceive() { + return newReceiveBuilder().onMessage(Create.class, this::onCreate).onMessage(Terminate.class, this::onTerminate).build(); } - private Behavior onCreate(Create command) { - //#create-actors - ActorRef a = this.getContext().spawn(ExampleActor.create("Alice"), "alice"); - ActorRef b = this.getContext().spawn(ExampleTimerActor.create(), "timeractor"); - //#create-actors + private Behavior onTerminate(Terminate msg) { + for (ActorRef actor : all_actors) { + actor.tell(new TimerActor.Terminate()); + } + return this; + } + + private Behavior onCreate(Create command) { + var alice = this.getContext().spawn(TimerActor.create("alice"), "alice"); + var bob = this.getContext().spawn(TimerActor.create("bob"), "bob"); + var charlie = this.getContext().spawn(TimerActor.create("charlie"), "charlie"); + + ArrayList> clock_reihenfolge = new ArrayList<>(); + clock_reihenfolge.add(bob); + clock_reihenfolge.add(charlie); + clock_reihenfolge.add(alice); + + ArrayList> counterclock_reihenfolge = new ArrayList<>(); + counterclock_reihenfolge.add(bob); + counterclock_reihenfolge.add(charlie); + counterclock_reihenfolge.add(alice); + + this.all_actors = new ArrayList<>(clock_reihenfolge); + alice.tell(new TimerActor.Clockwise(clock_reihenfolge)); + alice.tell(new TimerActor.CounterClockwise(counterclock_reihenfolge)); + + timers.startSingleTimer(new Terminate(), Duration.ofSeconds(60)); - a.tell(new ExampleActor.ExampleMessage(this.getContext().getSelf(),"Test123")); return this; } } diff --git a/src/main/java/com/example/AkkaStart.java b/src/main/java/com/example/AkkaStart.java index 45339c2..19ed5ac 100644 --- a/src/main/java/com/example/AkkaStart.java +++ b/src/main/java/com/example/AkkaStart.java @@ -5,7 +5,7 @@ import akka.actor.typed.ActorSystem; import java.io.IOException; public class AkkaStart { public static void main(String[] args) { - final ActorSystem messageMain = ActorSystem.create(AkkaMainSystem.create(), "akkaMainSystem"); + final ActorSystem messageMain = ActorSystem.create(AkkaMainSystem.create(), "akkaMainSystem"); messageMain.tell(new AkkaMainSystem.Create()); diff --git a/src/main/java/com/example/ExampleActor.java b/src/main/java/com/example/ExampleActor.java deleted file mode 100644 index cf56713..0000000 --- a/src/main/java/com/example/ExampleActor.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.example; - -import akka.actor.typed.ActorRef; -import akka.actor.typed.Behavior; -import akka.actor.typed.javadsl.*; - -public class ExampleActor extends AbstractBehavior { - - public interface Message {}; - - public record ExampleMessage(ActorRef someReference, String someString) implements Message { } - - public static Behavior create(String name) { - return Behaviors.setup(context -> new ExampleActor(context, name)); - } - - private final String name; - - private ExampleActor(ActorContext context, String name) { - super(context); - this.name = name; - } - - @Override - public Receive createReceive() { - return newReceiveBuilder() - .onMessage(ExampleMessage.class, this::onExampleMessage) - .build(); - } - - private Behavior onExampleMessage(ExampleMessage msg) { - getContext().getLog().info("I ({}) got a message: ExampleMessage({},{})", this.name, msg.someReference, msg.someString); - return this; - } -} diff --git a/src/main/java/com/example/ExampleTimerActor.java b/src/main/java/com/example/ExampleTimerActor.java deleted file mode 100644 index 0bffbea..0000000 --- a/src/main/java/com/example/ExampleTimerActor.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.example; - -import akka.actor.typed.javadsl.TimerScheduler; -import akka.actor.typed.Behavior; -import akka.actor.typed.javadsl.AbstractBehavior; -import akka.actor.typed.javadsl.ActorContext; -import akka.actor.typed.javadsl.Behaviors; -import akka.actor.typed.javadsl.Receive; - -import java.time.Duration; - - -public class ExampleTimerActor extends AbstractBehavior { - - public interface Message {}; - - - public record ExampleMessage(String someString) implements Message { } - - public static Behavior create() { - return Behaviors.setup(context -> Behaviors.withTimers(timers -> new ExampleTimerActor(context, timers))); - } - - private final TimerScheduler timers; - - private ExampleTimerActor(ActorContext context, TimerScheduler timers) { - super(context); - this.timers = timers; - - Message msg = new ExampleMessage("test123"); - this.timers.startSingleTimer(msg, msg, Duration.ofSeconds(10)); - } - - @Override - public Receive createReceive() { - return newReceiveBuilder() - .onMessage(ExampleMessage.class, this::onExampleMessage) - .build(); - } - - private Behavior onExampleMessage(ExampleMessage msg) { - getContext().getLog().info("I have send myself this message after 10 Seconds: {}", msg.someString); - return this; - } -} diff --git a/src/main/java/com/example/TimerActor.java b/src/main/java/com/example/TimerActor.java new file mode 100644 index 0000000..547d7e4 --- /dev/null +++ b/src/main/java/com/example/TimerActor.java @@ -0,0 +1,87 @@ +package com.example; + +import akka.actor.typed.ActorRef; +import akka.actor.typed.javadsl.TimerScheduler; +import akka.actor.typed.Behavior; +import akka.actor.typed.javadsl.AbstractBehavior; +import akka.actor.typed.javadsl.ActorContext; +import akka.actor.typed.javadsl.Behaviors; +import akka.actor.typed.javadsl.Receive; + +import java.time.Duration; +import java.util.ArrayList; + + +public class TimerActor extends AbstractBehavior { + + + public interface Message {}; + + public record Clockwise(ArrayList> reihenfolge) implements Message {} + public record CounterClockwise(ArrayList> reihenfolge) implements Message {} + public record Terminate() implements Message {} + + public record Clockwise_wait(ArrayList> reihenfolge) implements Message {} + public record CounterClockwise_wait(ArrayList> reihenfolge) implements Message {} + + public static Behavior create(String name) { + return Behaviors.setup(context -> Behaviors.withTimers(timers -> new TimerActor(context, timers, name))); + } + + private final TimerScheduler timers; + private final String name; + + private TimerActor(ActorContext context, TimerScheduler timers, String name) { + super(context); + this.timers = timers; + this.name = name; + } + + @Override + public Receive createReceive() { + return newReceiveBuilder() + .onMessage(Clockwise.class, this::onClockwise) + .onMessage(CounterClockwise.class, this::onCounterClockwise) + .onMessage(Clockwise_wait.class, this::onClockwise_wait) + .onMessage(CounterClockwise_wait.class, this::onCounterClockwise_wait) + .onMessage(Terminate.class, this::onTerminate) + .build(); + } + + private Behavior onClockwise(Clockwise msg) { + getContext().getLog().info("Clockwise erhalten"); + this.timers.startSingleTimer(new Clockwise_wait(msg.reihenfolge), Duration.ofSeconds(3)); + return this; + } + + private Behavior onClockwise_wait(Clockwise_wait msg) { + getContext().getLog().info("Clockwise senden"); + var new_reihenfolge = msg.reihenfolge; + var next = new_reihenfolge.remove(0); + new_reihenfolge.add(next); + + next.tell(new Clockwise(new_reihenfolge)); + return this; + } + + private Behavior onCounterClockwise(CounterClockwise msg) { + getContext().getLog().info("CounterClockwise erhalten"); + this.timers.startSingleTimer(new CounterClockwise_wait(msg.reihenfolge), Duration.ofSeconds(5)); + return this; + } + + private Behavior onCounterClockwise_wait(CounterClockwise_wait msg) { + getContext().getLog().info("CounterClockwise senden"); + var new_reihenfolge = msg.reihenfolge; + var next = new_reihenfolge.remove(0); + new_reihenfolge.add(next); + + next.tell(new CounterClockwise(new_reihenfolge)); + return this; + } + + private Behavior onTerminate(Terminate msg) { + getContext().getLog().info("Terminate"); + return Behaviors.stopped(); + } +}