From 6493ec8d2659183c8a64b1d4d7b504a2007e7909 Mon Sep 17 00:00:00 2001 From: olhag Date: Fri, 17 May 2024 01:18:02 +0200 Subject: [PATCH] complete TODOs and rewrite AkkaMainSystem --- .idea/.gitignore | 3 + .idea/compiler.xml | 6 ++ .idea/gradle.xml | 16 ++++ .idea/jarRepositories.xml | 30 +++++++ .idea/misc.xml | 5 ++ .idea/runConfigurations.xml | 10 +++ .idea/vcs.xml | 6 ++ src/main/java/com/example/AddressBook.java | 51 ++++++----- src/main/java/com/example/AkkaMainSystem.java | 40 ++++++--- src/main/java/com/example/Customer.java | 24 +++-- src/main/java/com/example/DeliveryCar.java | 87 +++++++++++-------- .../java/com/example/DistributionCenter.java | 49 ++++++++++- src/main/java/com/example/ExampleActor.java | 66 ++++++++++++-- src/main/java/com/example/Paket.java | 12 ++- 14 files changed, 324 insertions(+), 81 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..659bf43 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..ba1ec5c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..49bcecd --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..84c523c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..797acea --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/com/example/AddressBook.java b/src/main/java/com/example/AddressBook.java index aa69e19..68c68a2 100644 --- a/src/main/java/com/example/AddressBook.java +++ b/src/main/java/com/example/AddressBook.java @@ -10,44 +10,51 @@ import akka.actor.typed.javadsl.Receive; import java.util.ArrayList; import java.util.Random; - public class AddressBook extends AbstractBehavior { ArrayList> customers = new ArrayList<>(); + public interface Message {} - //Message, wenn ein Empfänger nach einer Adresse fragt - public record CustomerMessage(ActorRef fragender, String nameFragender,ActorRef truckReference) implements Message{} + // Nachricht, wenn ein Empfänger nach einer Adresse fragt + public static final class CustomerMessage implements Message { + public final ActorRef fragender; + public final String nameFragender; + public final ActorRef truckReference; - @Override - public Receive createReceive() { - return newReceiveBuilder() - .onMessage(CustomerMessage.class, this::onCustomerMessage) - .build(); + public CustomerMessage(ActorRef fragender, String nameFragender, ActorRef truckReference) { + this.fragender = fragender; + this.nameFragender = nameFragender; + this.truckReference = truckReference; + } } - //create Methode mit custo = der Liste der Empfänger - public static Behavior create(ArrayList> custo){ - return Behaviors.setup(context -> new AddressBook(context, custo)); - } - - //Konstruktor von dem Adressbuch, in dem auch jedem Customer direkt eine Hello Nachricht geschickt wird, damit diese - //das Adressbuch auch kennen (um nach Empfängern fragen zu können). - private AddressBook(ActorContext context, ArrayList> custo){ + private AddressBook(ActorContext context, ArrayList> custo) { super(context); - if(!custo.isEmpty()){ + if (!custo.isEmpty()) { this.customers.addAll(custo); - for (ActorRef cst: this.customers) { + for (ActorRef cst : this.customers) { cst.tell(new Customer.AddressHello(getContext().getSelf())); } } } - //Methode, um einen zufälligen Empfänger auszugeben - public Behavior onCustomerMessage(CustomerMessage msg){ + public static Behavior create(ArrayList> custo) { + return Behaviors.setup(context -> new AddressBook(context, custo)); + } + + @Override + public Receive createReceive() { + return newReceiveBuilder() + .onMessage(CustomerMessage.class, this::onCustomerMessage) + .build(); + } + + // Methode, um einen zufälligen Empfänger auszugeben + private Behavior onCustomerMessage(CustomerMessage msg) { Random random = new Random(); int index = random.nextInt(customers.size()); - var addressOf = customers.get(index); - getContext().getLog().info("{} asked for an address",msg.nameFragender); + ActorRef addressOf = customers.get(index); + getContext().getLog().info("{} asked for an address", msg.nameFragender); msg.fragender.tell(new Customer.AddressMessage(addressOf, msg.truckReference)); return this; } diff --git a/src/main/java/com/example/AkkaMainSystem.java b/src/main/java/com/example/AkkaMainSystem.java index 55a086e..134e8c2 100644 --- a/src/main/java/com/example/AkkaMainSystem.java +++ b/src/main/java/com/example/AkkaMainSystem.java @@ -5,7 +5,8 @@ import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.*; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; +import java.util.List; public class AkkaMainSystem extends AbstractBehavior { @@ -25,16 +26,35 @@ public class AkkaMainSystem extends AbstractBehavior { return newReceiveBuilder().onMessage(Create.class, this::onCreate).build(); } + private Behavior onCreate(Create command) { - //#create-actors - ActorRef a = this.getContext().spawn(Customer.create("Alice"), "alice"); - ActorRef b = this.getContext().spawn(Customer.create("Bob"), "bob"); - ActorRef c = this.getContext().spawn(Customer.create("Charlie"), "charlie"); - ActorRef d = this.getContext().spawn(Customer.create("Derik"), "derik"); - ActorRef timerActor = this.getContext().spawn(ExampleTimerActor.create(), "timeractor"); - //#create-actors - ArrayList> actors = new ArrayList<>(Arrays.asList(a,b,c,d)); - ActorRef addressBook = this.getContext().spawn(AddressBook.create(actors), "addressbook"); + + // Erstellen des Adressbuchs + ArrayList> customers = new ArrayList<>(); + ActorRef addressBook = getContext().spawn(AddressBook.create(customers), "addressBook"); + + // Erstellen von vier Empfänger*innen + for (int i = 0; i < 4; i++) { + customers.add(getContext().spawn(Customer.create("Customer" + (i + 1)), "customer" + (i + 1))); + } + + // Erstellen des Verteilzentrums + ActorRef distributionCenter = getContext().spawn(DistributionCenter.create(), "distributionCenter"); + + // Erstellen von vier Wagen mit zufälligen Routen + for (int i = 0; i < 4; i++) { + List> route = new ArrayList<>(customers); + Collections.shuffle(route); + ActorRef truck = getContext().spawn(DeliveryCar.create(route), "truck" + (i + 1)); + // Erstellen einer leeren Paketliste + List paketeList = new ArrayList<>(); + paketeList.add(new Paket("Inhalt 1")); + paketeList.add(new Paket("Inhalt 2")); + // Beispiel für den Aufruf der ArriveMessage-Nachricht mit korrekten Parametern + distributionCenter.tell(new DistributionCenter.ArriveMessage(paketeList, truck)); + + } + return this; } } diff --git a/src/main/java/com/example/Customer.java b/src/main/java/com/example/Customer.java index cc391f4..51ac188 100644 --- a/src/main/java/com/example/Customer.java +++ b/src/main/java/com/example/Customer.java @@ -14,16 +14,30 @@ import java.util.Random; public class Customer extends AbstractBehavior { String name; - ActorRef adrBook; ArrayList gegenstaende = new ArrayList<>(Arrays.asList("Spülmaschine","Altes CD-Regal", "Goldbarren","20kg Hanteln", "Holzkohlegrill","Blumenerde")); public interface Message {} //Delivery Nachricht Typ - public record DeliveryMessage(Paket paket) implements Message {} - //Pickup Nachricht Typ - public record PickUpMessage(ActorRef truckReference, String someString) implements Message {} + public static final class DeliveryMessage implements Message { + public final Paket paket; + + public DeliveryMessage(Paket paket) { + this.paket = paket; + } + } + + //Pickup Nachricht Typ + public static final class PickUpMessage implements Message { + public final ActorRef truckReference; + public final String someString; + + public PickUpMessage(ActorRef truckReference, String someString) { + this.truckReference = truckReference; + this.someString = someString; + } + } public record AddressHello(ActorRef book) implements Message {} public record AddressMessage(ActorRef addresse, ActorRef truckReference) implements Message {} @@ -64,7 +78,7 @@ public class Customer extends AbstractBehavior { //truck wird hier übergeben, damit man im nächsten Schritt wieder auf ihn zugreifen kann. this.adrBook.tell(new AddressBook.CustomerMessage(getContext().getSelf(), this.name, msg.truckReference)); }else{ - msg.truckReference.tell(new DeliveryCar.PickupResponse(null)); + msg.truckReference.tell(new DeliveryCar.PickupResponse(null)); } return this; } diff --git a/src/main/java/com/example/DeliveryCar.java b/src/main/java/com/example/DeliveryCar.java index 1b2f8d1..4b1d4f6 100644 --- a/src/main/java/com/example/DeliveryCar.java +++ b/src/main/java/com/example/DeliveryCar.java @@ -4,59 +4,78 @@ import akka.actor.typed.ActorRef; 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.util.ArrayList; +import java.util.List; -//TODO: Timer Aktivitäten müssen hinzugefügt werden -//TODO: Delivery Nachricht für den Fall, dass der Truck ein Paket für den Customer hat, bei dem der Truck gerade ist -//Gedanke: Eventuell mit Overseer wie in Blatt 1 arbeiten für das Einhalten der Routen -//TODO: Pickup Nachricht an den Customer, wenn der Truck noch freie Plätze hat -//TODO: Arrive Nachricht public class DeliveryCar extends AbstractBehavior { - ArrayList pakete; - ArrayList> route; + private final ArrayList pakete = new ArrayList<>(); + private final ArrayList> route; + private final int maxCapacity = 3; - public record LoadMessage(ArrayList pakete) implements Message{} public interface Message {} - public record PickupResponse(Paket paket) implements Message{} + public record LoadMessage(List pakete) implements Message {} + + public record PickupResponse(Paket paket) implements Message {} + + public record ContinueRoute() implements Message {} + + private DeliveryCar(ActorContext context, ArrayList> route) { + super(context); + this.route = route; + } + + public static Behavior create(List> route) { + return Behaviors.setup(context -> new DeliveryCar(context, new ArrayList<>(route))); + } + @Override public Receive createReceive() { return newReceiveBuilder() + .onMessage(LoadMessage.class, this::onLoadMessage) .onMessage(PickupResponse.class, this::onPickupResponse) + .onMessage(ContinueRoute.class, msg -> { + deliverPackages(); + return Behaviors.same(); + }) .build(); } - private DeliveryCar(ActorContext context,ArrayList> route){ - super(context); - this.route = route; - - } - - //Pakete aus dem Verteilzentrum einladen - //TODO: Eventuell das losfahren und handlen, zu welchem Empfänger er fahren muss, mit einem Overseer Actor implementieren - public Behavior onLoadMessage(LoadMessage msg){ - if(!msg.pakete.isEmpty()){ - this.pakete.addAll(msg.pakete); - } - //vielleicht sowas wie in Blatt 1 Lösung mit einem Overseer Actor und dann einem overseer Attribut im Konstruktor - //this.overseer.tell(new Overseer.LoadedMessage() + private Behavior onLoadMessage(LoadMessage msg) { + pakete.addAll(msg.pakete); + checkNextStop(); return this; } - //Customer gibt PickupResponse entweder mit einem Paket oder ohne eins - //Die Methode kann nur ausgeführt werden, wenn zuvor eine Pickup Nachricht an den Empfänger gesendet wurde und das - //impliziert, dass der Truck noch Platz für weitere Pakete hat - public Behavior onPickupResponse(PickupResponse rsp){ - if(rsp.paket != null){ - pakete.add(rsp.paket); - getContext().getLog().info("Aktuelle Anzahl der Pakete im Truck: {}",pakete.size()); - } - //TODO: Fall behandeln, dass kein Paket übergeben wurde (wahrscheinlich einfach Timer setzen) + private Behavior onPickupResponse(PickupResponse rsp) { + pakete.add(rsp.paket); + getContext().getLog().info("Aktuelle Anzahl der Pakete im Truck: {}", pakete.size()); + checkNextStop(); return this; } -} + private void checkNextStop() { + if (pakete.size() >= maxCapacity || route.isEmpty()) { + getContext().getSelf().tell(new ContinueRoute()); + } else { + sendPickupMessage(); + } + } + + private void sendPickupMessage() { + ActorRef nextCustomer = route.remove(0); + nextCustomer.tell(new Customer.PickUpMessage(getContext().getSelf(), "Some string")); + } + + private void deliverPackages() { + ActorRef nextCustomer = route.get(0); + for (Paket paket : pakete) { + nextCustomer.tell(new Customer.DeliveryMessage(paket)); + } + pakete.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/DistributionCenter.java b/src/main/java/com/example/DistributionCenter.java index 26f4f41..64dbd3a 100644 --- a/src/main/java/com/example/DistributionCenter.java +++ b/src/main/java/com/example/DistributionCenter.java @@ -1,21 +1,62 @@ package com.example; +import akka.actor.typed.ActorRef; +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; - //TODO: Implementierung dieser Klasse +import java.util.ArrayList; +import java.util.List; + public class DistributionCenter extends AbstractBehavior { - public DistributionCenter(ActorContext context) { + public static class ArriveMessage implements Message { + private final List pakete; + private final ActorRef truck; + + public ArriveMessage(List pakete, ActorRef truck) { + this.pakete = pakete; + this.truck = truck; + } + + public List getPakete() { + return pakete; + } + + public ActorRef getTruck() { + return truck; + } + } + + private DistributionCenter(ActorContext context) { super(context); } - interface Message{} + interface Message {} + public static Behavior create() { + return Behaviors.setup(DistributionCenter::new); + } @Override public Receive createReceive() { - return newReceiveBuilder().build(); + return newReceiveBuilder() + .onMessage(ArriveMessage.class, this::onArriveMessage) + .build(); + } + + private Behavior onArriveMessage(ArriveMessage msg) { + // Füge alle Pakete aus der Ankunftsnachricht dem Lagerraum hinzu + List pakete = msg.getPakete(); + getContext().getLog().info("Angekommene Pakete: {}", pakete); + + // Hier kann die weitere Logik für die Behandlung der Pakete implementiert werden + + // Beispiel: Senden der Pakete an einen internen Akteur zur weiteren Verarbeitung + // ... + + return this; } } diff --git a/src/main/java/com/example/ExampleActor.java b/src/main/java/com/example/ExampleActor.java index cf56713..49cea24 100644 --- a/src/main/java/com/example/ExampleActor.java +++ b/src/main/java/com/example/ExampleActor.java @@ -3,28 +3,61 @@ package com.example; import akka.actor.typed.ActorRef; import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.*; +import akka.io.dns.internal.Message; + +import java.util.ArrayList; +import java.util.Random; + + +import static com.example.AkkaMainSystem.*; public class ExampleActor extends AbstractBehavior { - public interface Message {}; + public interface Message {} - public record ExampleMessage(ActorRef someReference, String someString) implements Message { } + public record ExampleMessage(ActorRef someReference, String someString) implements Message { } + public record Customer(String name, ActorRef reference) {} - public static Behavior create(String name) { - return Behaviors.setup(context -> new ExampleActor(context, name)); + // Nachricht, um eine Empfängerreferenz hinzuzufügen + public static class AddCustomer implements Message { + private final ActorRef customer; + + public AddCustomer(ActorRef customer) { + this.customer = customer; + } + + public ActorRef getCustomer() { + return customer; + } } private final String name; + public static class PrintCustomers implements Message {} + private final ArrayList> customers; // ArrayList aller Empfänger*innen + private final Random random; + public static class PrintRandomCustomer implements Message {}// Nachricht, um einen zufälligen Kunden auszugeben + + + private ExampleActor(ActorContext context, String name) { super(context); this.name = name; + this.customers = new ArrayList<>(); + this.random = new Random(); + } + + public static Behavior create(String name) { + return Behaviors.setup(context -> new ExampleActor(context, name)); } @Override public Receive createReceive() { return newReceiveBuilder() .onMessage(ExampleMessage.class, this::onExampleMessage) + .onMessage(AddCustomer.class, this::onAddCustomer) + .onMessage(PrintCustomers.class, this::onPrintCustomers) + .onMessage(PrintRandomCustomer.class, this::onPrintRandomCustomer) .build(); } @@ -32,4 +65,27 @@ public class ExampleActor extends AbstractBehavior { getContext().getLog().info("I ({}) got a message: ExampleMessage({},{})", this.name, msg.someReference, msg.someString); return this; } -} + + + private Behavior onAddCustomer(AddCustomer msg) { + customers.add(msg.getCustomer()); + return this; + } + + private Behavior onPrintCustomers(PrintCustomers msg) { + for (ActorRef customer : customers) { + getContext().getLog().info("Customer: {}", customer.path().name()); + } + return this; + } + private Behavior onPrintRandomCustomer(PrintRandomCustomer msg) { + if (!customers.isEmpty()) { + int randomIndex = random.nextInt(customers.size()); + ActorRef randomCustomer = customers.get(randomIndex); + getContext().getLog().info("Random Customer: {}", randomCustomer.path().name()); + } else { + getContext().getLog().info("No customers available."); + } + return this; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/Paket.java b/src/main/java/com/example/Paket.java index e4754e8..9181cbf 100644 --- a/src/main/java/com/example/Paket.java +++ b/src/main/java/com/example/Paket.java @@ -2,14 +2,24 @@ package com.example; import akka.actor.typed.ActorRef; + public class Paket { String inhalt; String absender; ActorRef empfaenger; - Paket(String inhalt, String absender, ActorRef empfaenger){ + // Konstruktor, der nur den Inhalt annimmt + Paket(String inhalt) { + this.inhalt = inhalt; + this.absender = null; // Absender und Empfänger können optional sein + this.empfaenger = null; + } + + // Konstruktor mit allen Parametern + Paket(String inhalt, String absender, ActorRef empfaenger) { this.inhalt = inhalt; this.absender = absender; this.empfaenger = empfaenger; } } +