This commit is contained in:
olhag 2024-05-19 19:53:49 +02:00
parent e07514241f
commit 7c249dd5e4
34 changed files with 304 additions and 45 deletions

Binary file not shown.

View File

@ -12,16 +12,26 @@ import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* AddressBook Actor class that maintains a list of customers and handles messages related to customer addresses.
* This actor can respond to requests for customer addresses and can provide the list of all customers.
*/
public class AddressBook extends AbstractBehavior<AddressBook.Message> {
private final ArrayList<ActorRef<Customer.Message>> customers;
/**
* Interface for all messages that AddressBook can handle.
*/
public interface Message {}
// Nachricht, wenn ein Empfänger nach einer Adresse fragt
/**
* Message sent by a customer asking for a random address from the AddressBook.
*/
public static final class CustomerMessage implements Message {
public final ActorRef<Customer.Message> fragender;
public final String nameFragender;
public final ActorRef<DeliveryCar.Message> truckReference;
public final ActorRef<Customer.Message> fragender; // The customer actor sending the message
public final String nameFragender; // The name of the customer
public final ActorRef<DeliveryCar.Message> truckReference; // Reference to the delivery car
public CustomerMessage(ActorRef<Customer.Message> fragender, String nameFragender, ActorRef<DeliveryCar.Message> truckReference) {
this.fragender = fragender;
@ -30,23 +40,39 @@ public class AddressBook extends AbstractBehavior<AddressBook.Message> {
}
}
// Nachricht, um die Liste der Kunden abzurufen
/**
* Message to request the list of all customers.
*/
public static final class GetCustomers implements Message {
public final ActorRef<List<ActorRef<Customer.Message>>> replyTo;
public final ActorRef<List<ActorRef<Customer.Message>>> replyTo; // Actor to reply to with the list of customers
public GetCustomers(ActorRef<List<ActorRef<Customer.Message>>> replyTo) {
this.replyTo = replyTo;
}
}
/**
* Constructor for AddressBook.
* Initializes the AddressBook with a list of customer actors and sends each customer an AddressHello message.
*
* @param context the actor context
* @param customers the list of customer actors
*/
private AddressBook(ActorContext<Message> context, ArrayList<ActorRef<Customer.Message>> customers) {
super(context);
this.customers = new ArrayList<>(customers);
// Notify each customer with an AddressHello message
for (ActorRef<Customer.Message> cst : this.customers) {
cst.tell(new Customer.AddressHello(getContext().getSelf()));
}
}
/**
* Factory method to create a new AddressBook actor.
*
* @param customers the list of customer actors
* @return the behavior of the AddressBook actor
*/
public static Behavior<Message> create(ArrayList<ActorRef<Customer.Message>> customers) {
return Behaviors.setup(context -> new AddressBook(context, customers));
}
@ -59,19 +85,29 @@ public class AddressBook extends AbstractBehavior<AddressBook.Message> {
.build();
}
// Methode, um einen zufälligen Empfänger auszugeben
/**
* Handles CustomerMessage by selecting a random customer from the list and sending their address to the requesting customer.
*
* @param msg the customer message requesting a random address
* @return the behavior of the AddressBook actor
*/
private Behavior<Message> onCustomerMessage(CustomerMessage msg) {
Random random = new Random();
int index = random.nextInt(customers.size());
ActorRef<Customer.Message> addressOf = customers.get(index);
getContext().getLog().info("{} hat nach einer Addresse gefragt CAR: {} ", msg.nameFragender, msg.truckReference.path().name());
getContext().getLog().info("{} hat nach einer Adresse gefragt CAR: {}", msg.nameFragender, msg.truckReference.path().name());
msg.fragender.tell(new Customer.AddressMessage(addressOf, msg.truckReference));
return this;
}
// Methode, um die Liste der Kunden zu senden
/**
* Handles GetCustomers message by replying with the unmodifiable list of customers.
*
* @param msg the get customers message
* @return the behavior of the AddressBook actor
*/
private Behavior<Message> onGetCustomers(GetCustomers msg) {
msg.replyTo.tell(Collections.unmodifiableList(customers));
return this;
}
}
}

View File

@ -5,45 +5,75 @@ import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.*;
import java.util.ArrayList;
import java.util.List;
/**
* AkkaMainSystem Actor class that initializes the system with customers, an address book, and a distribution center.
*/
public class AkkaMainSystem extends AbstractBehavior<AkkaMainSystem.Create> {
/**
* Message to trigger the creation of the AkkaMainSystem.
*/
public static class Create {}
/**
* Factory method to create a new AkkaMainSystem actor.
*
* @return the behavior of the AkkaMainSystem actor
*/
public static Behavior<Create> create() {
return Behaviors.setup(AkkaMainSystem::new);
}
// Statische Referenz auf das DistributionCenter
// Static reference to the DistributionCenter actor
private static ActorRef<DistributionCenter.Message> distributionCenter;
// Statische Methode zum Abrufen der DistributionCenter-Referenz
/**
* Static method to retrieve the reference of the DistributionCenter actor.
*
* @return the DistributionCenter actor reference
*/
public static ActorRef<DistributionCenter.Message> getDistributionCenter() {
return distributionCenter;
}
/**
* Constructor for AkkaMainSystem.
* Initializes the system by creating customers, an address book, and a distribution center.
*
* @param context the actor context
*/
private AkkaMainSystem(ActorContext<Create> context) {
super(context);
// Erstellen des Adressbuchs
// Creating the list of customer actors
ArrayList<ActorRef<Customer.Message>> customers = new ArrayList<>();
customers.add(getContext().spawn(Customer.create("Alice"), "alice"));
customers.add(getContext().spawn(Customer.create("Bob"), "bob"));
customers.add(getContext().spawn(Customer.create("Charles"), "charles"));
customers.add(getContext().spawn(Customer.create("Derick"), "derick"));
// Creating the AddressBook actor with the list of customers
ActorRef<AddressBook.Message> addressBook = getContext().spawn(AddressBook.create(customers), "addressBook");
// Erstellen des Verteilzentrums
// Creating the DistributionCenter actor with the address book reference
distributionCenter = getContext().spawn(DistributionCenter.create(addressBook), "distributionCenter");
}
@Override
public Receive<Create> createReceive() {
return newReceiveBuilder().onMessage(Create.class, this::onCreate).build();
return newReceiveBuilder()
.onMessage(Create.class, this::onCreate)
.build();
}
/**
* Handles the Create message. Additional setup can be done here if needed.
*
* @param command the create command
* @return the behavior of the AkkaMainSystem actor
*/
private Behavior<Create> onCreate(Create command) {
// Additional setup if needed
return this;

View File

@ -11,15 +11,24 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
/**
* Customer Actor class that simulates a customer in the system.
* This actor can receive packages, send packages, and interact with an address book.
*/
public class Customer extends AbstractBehavior<Customer.Message> {
String name;
ActorRef<AddressBook.Message> adrBook;
ArrayList<String> gegenstaende = new ArrayList<>(Arrays.asList("Spülmaschine","Altes CD-Regal", "Goldbarren","20kg Hanteln", "Holzkohlegrill","Blumenerde"));
/**
* Interface for all messages that Customer can handle.
*/
public interface Message {}
//Delivery Nachricht Typ
/**
* Message representing a delivery of a package to the customer.
*/
public static final class DeliveryMessage implements Message {
public final Paket paket;
@ -28,7 +37,9 @@ public class Customer extends AbstractBehavior<Customer.Message> {
}
}
//Pickup Nachricht Typ
/**
* Message representing a request to pick up a package from the customer.
*/
public static final class PickUpMessage implements Message {
public final ActorRef<DeliveryCar.Message> truckReference;
public final String someString;
@ -42,11 +53,25 @@ public class Customer extends AbstractBehavior<Customer.Message> {
public record AddressHello(ActorRef<AddressBook.Message> book) implements Message {}
public record AddressMessage(ActorRef<Customer.Message> addresse, ActorRef<DeliveryCar.Message> truckReference) implements Message {}
/**
* Constructor for Customer.
* Initializes the customer with a name.
*
* @param context the actor context
* @param name the name of the customer
*/
private Customer(ActorContext<Message> context, String name){
super(context);
this.name = name;
}
/**
* Factory method to create a new Customer actor.
*
* @param name the name of the customer
* @return the behavior of the Customer actor
*/
public static Behavior<Customer.Message> create(String name) {
return Behaviors.setup(context -> new Customer(context, name));
}
@ -62,15 +87,26 @@ public class Customer extends AbstractBehavior<Customer.Message> {
.build();
}
//Hier wird das Adressbuch gespeichert, nachdem es sich gemeldet hat
/**
* Stores the address book reference when received.
*
* @param msg the AddressHello message
* @return the behavior of the Customer actor
*/
private Behavior<Message> onAddressHello(AddressHello msg){
this.adrBook = msg.book;
return this;
}
//Verhalten, wenn Pickup Nachricht eingegangen ist
//Wenn 80% getroffen wurden, wird eine Anfrage an das Adressbuch geschickt und die Antwort
// an anderer Stelle (onAddressMessage) verarbeitet, um das Paket zu verschicken
/**
* Handles the PickUpMessage by deciding whether to send a package.
* If a random number is less than or equal to 80, a request is sent to the address book
* to get a random customer address, and the package is then sent.
* Otherwise, logs that no package will be sent.
*
* @param msg the PickUpMessage
* @return the behavior of the Customer actor
*/
private Behavior<Message> onPickUpMessage(PickUpMessage msg){
getContext().getLog().info("Kunde {}, will kein Paket abschicken CAR: {}", this.name, msg.truckReference.path().name());
Random random = new Random();
@ -89,7 +125,12 @@ public class Customer extends AbstractBehavior<Customer.Message> {
return this;
}
//Adresse des Empfängers von dem Adressbuch empfangen und das Paket wird in den Truck geladen und verschickt
/**
* Handles the AddressMessage by creating a package with a random item and sending it to the truck.
*
* @param adr the AddressMessage
* @return the behavior of the Customer actor
*/
private Behavior<Message> onAddressMessage(AddressMessage adr){
Random random = new Random();
int index = random.nextInt(gegenstaende.size());
@ -100,7 +141,12 @@ public class Customer extends AbstractBehavior<Customer.Message> {
return this;
}
//Verhalten, wenn Paket eingegangen ist
/**
* Handles the DeliveryMessage by logging the received package details.
*
* @param pkt the DeliveryMessage
* @return the behavior of the Customer actor
*/
private Behavior<Message> onDeliveryMessage(DeliveryMessage pkt){
getContext().getLog().info("Ich habe ein Paket von {} erhalten mit dem Inhalt: {} ", pkt.paket.absender, pkt.paket.inhalt);
return this;

View File

@ -10,36 +10,77 @@ import java.util.List;
import static com.example.AkkaMainSystem.getDistributionCenter;
/**
* DeliveryCar class that simulates a delivery car in the system.
* This actor can load packages, follow a delivery route, and pick up packages from customers.
*/
public class DeliveryCar extends AbstractBehavior<DeliveryCar.Message> {
// Liste der Pakete im Lieferwagen
private final ArrayList<Paket> pakete = new ArrayList<>();
// Route mit Kunden, die abgefahren wird
private final ArrayList<ActorRef<Customer.Message>> route;
// Maximale Kapazität des Lieferwagens
private final int maxCapacity = 3;
// Timer zum Planen von Zustellungen
private final TimerScheduler<Message> timers;
// Globaler Index für die aktuelle Position auf der Route
private int globalIndex = 0;
/**
* Interface for all messages that DeliveryCar can handle.
*/
public interface Message {}
/**
* Message to load packages into the delivery car.
*/
public record LoadMessage(List<Paket> pakete) implements Message {}
/**
* Message representing the response from a customer when a package is picked up.
*/
public record PickupResponse(Paket paket) implements Message {}
/**
* Message to start the delivery route.
*/
public record StartRoute() implements Message {}
/**
* Message to check the next stop on the route.
*/
public record CheckStop() implements Message {}
public record Clear() implements Message {} // Clear all packages in the delivery car
/**
* Message to clear all packages in the delivery car.
*/
public record Clear() implements Message {}
/**
* Constructor for DeliveryCar.
*
* @param context the actor context
* @param timers the timer scheduler
* @param route the delivery route
*/
private DeliveryCar(ActorContext<Message> context, TimerScheduler<Message> timers, ArrayList<ActorRef<Customer.Message>> route) {
super(context);
this.route = route;
this.timers = timers;
}
/**
* Factory method to create a new DeliveryCar actor.
*
* @param route the delivery route
* @return the behavior of the DeliveryCar actor
*/
public static Behavior<Message> create(List<ActorRef<Customer.Message>> route) {
return Behaviors.setup(context -> Behaviors.withTimers(timers -> new DeliveryCar(context, timers, new ArrayList<>(route))));
}
// Handling of the various messages the DeliveryCar can receive
@Override
public Receive<Message> createReceive() {
return newReceiveBuilder()
@ -51,7 +92,12 @@ public class DeliveryCar extends AbstractBehavior<DeliveryCar.Message> {
.build();
}
//Nachricht, um Pakete zu beladen von DistributionCenter z.B.
/**
* Handles the LoadMessage to load packages into the delivery car.
*
* @param msg the LoadMessage
* @return the behavior of the DeliveryCar actor
*/
private Behavior<Message> onLoadMessage(LoadMessage msg) {
pakete.addAll(msg.pakete);
getContext().getLog().info("Laden: {} Pakete wurden in den LKW geladen.", msg.pakete.size());
@ -59,8 +105,12 @@ public class DeliveryCar extends AbstractBehavior<DeliveryCar.Message> {
return this;
}
//Die Nachricht, die den Paket, vom Kunden abholt und in den Wagen lädt
/**
* Handles the PickupResponse to pick up a package from a customer.
*
* @param rsp the PickupResponse
* @return the behavior of the DeliveryCar actor
*/
private Behavior<Message> onPickupResponse(PickupResponse rsp) {
if (rsp.paket != null && rsp.paket.inhalt != null && pakete.size() < maxCapacity) {
pakete.add(rsp.paket);
@ -70,7 +120,13 @@ public class DeliveryCar extends AbstractBehavior<DeliveryCar.Message> {
return this;
}
//Prüft, ob der Wagen schon alle Addressen durchgegangen ist und geht zum Verteilerzentrum, sonst. geht dieser seine Route weiter
/**
* Checks if the delivery car has completed the route and returns to the distribution center.
* Otherwise, it moves to the next stop.
*
* @param stop the CheckStop message
* @return the behavior of the DeliveryCar actor
*/
private Behavior<Message> onCheckStop(CheckStop stop) {
if (globalIndex >= route.size()) {
getContext().getLog().info("Rückkehr: Der LKW kehrt zum Verteilzentrum zurück mit {} Paketen.", pakete.size());
@ -90,26 +146,43 @@ public class DeliveryCar extends AbstractBehavior<DeliveryCar.Message> {
return this;
}
//Methode, um die Autos zu "starten"
/**
* Starts the delivery route.
*
* @param msg the StartRoute message
* @return the behavior of the DeliveryCar actor
*/
private Behavior<Message> onStartRoute(StartRoute msg) {
globalIndex = 0;
scheduleNextStopCheck(Duration.ofSeconds(3)); // Start checking the first stop after 3 seconds
return this;
}
//
/**
* Clears all packages in the delivery car.
*
* @param clear the Clear message
* @return the behavior of the DeliveryCar actor
*/
private Behavior<Message> onClear(Clear clear) {
pakete.clear();
return this;
}
//Sendet eine Nachricht an Customer bzw. an einen Addressaten, wo der Wagen steht, und fragt ob ein Paket von denen geliefert werden soll
/**
* Sends a pickup message to a customer to ask if they have a package to send.
*
* @param customer the customer actor reference
*/
private void sendPickupMessage(ActorRef<Customer.Message> customer) {
customer.tell(new Customer.PickUpMessage(getContext().getSelf(), "Der LKW kann das Paket abholen."));
}
//Liefert Paket aus, die im Wagen ist
/**
* Delivers packages that are meant for the current customer.
*
* @param customer the customer actor reference
*/
private void deliverPackages(ActorRef<Customer.Message> customer) {
pakete.removeIf(paket -> {
if (paket.empfaenger.equals(customer)) {
@ -120,7 +193,11 @@ public class DeliveryCar extends AbstractBehavior<DeliveryCar.Message> {
});
}
//Private Methode für den Timer
/**
* Schedules the next stop check after a given duration.
*
* @param duration the duration after which to check the next stop
*/
private void scheduleNextStopCheck(Duration duration) {
timers.startSingleTimer(new CheckStop(), duration);
}

View File

@ -11,14 +11,27 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Die Klasse `DistributionCenter` repräsentiert das Verteilzentrum im System.
* Das Verteilzentrum empfängt Pakete von Lieferwagen, speichert sie und generiert Routen für Lieferwagen.
*/
public class DistributionCenter extends AbstractBehavior<DistributionCenter.Message> {
// Referenz auf das Adressbuch
private final ActorRef<AddressBook.Message> addressBook;
public static class StartAllRoutes implements Message {}
// Liste der Pakete im Lager
private final List<Paket> lagerraum = new ArrayList<>();
// Liste der Lieferwagen
private final List<ActorRef<DeliveryCar.Message>> deliveryCars = new ArrayList<>();
public static class StartAllRoutes implements Message {}
/**
* Konstruktor für das Verteilzentrum.
*
* @param context das Actor-Kontext
* @param addressBook Referenz auf das Adressbuch
*/
private DistributionCenter(ActorContext<Message> context, ActorRef<AddressBook.Message> addressBook) {
super(context);
this.addressBook = addressBook;
@ -40,12 +53,21 @@ public class DistributionCenter extends AbstractBehavior<DistributionCenter.Mess
addressBook.tell(new AddressBook.GetCustomers(replyTo));
}
/**
* Factory-Methode zur Erstellung eines neuen Verteilzentrums-Akteurs.
*
* @param addressBook Referenz auf das Adressbuch
* @return das Verhalten des Verteilzentrums-Akteurs
*/
public static Behavior<Message> create(ActorRef<AddressBook.Message> addressBook) {
return Behaviors.setup(context -> new DistributionCenter(context, addressBook));
}
// Definition der Nachrichten für das Verteilzentrum
interface Message {}
/**
* Nachricht, die ankommende Pakete vom Lieferwagen enthält.
*/
public static class ArriveMessage implements Message {
private final List<Paket> pakete;
private final ActorRef<DeliveryCar.Message> truck;
@ -64,6 +86,9 @@ public class DistributionCenter extends AbstractBehavior<DistributionCenter.Mess
}
}
/**
* Nachricht zur Generierung von Routen für Lieferwagen.
*/
public static class GenerateRoutes implements Message {
private final List<ActorRef<Customer.Message>> customers;
@ -85,6 +110,12 @@ public class DistributionCenter extends AbstractBehavior<DistributionCenter.Mess
.build();
}
/**
* Handhabt die Ankunftsnachricht vom Lieferwagen.
*
* @param msg die Ankunftsnachricht
* @return das Verhalten des Verteilzentrums
*/
private Behavior<Message> onArriveMessage(ArriveMessage msg) {
// Füge alle Pakete aus der Ankunftsnachricht dem Lagerraum hinzu
List<Paket> arrivedPackages = msg.getPakete();
@ -106,12 +137,23 @@ public class DistributionCenter extends AbstractBehavior<DistributionCenter.Mess
return this;
}
/**
* Handhabt die Nachricht zur Generierung von Routen.
*
* @param msg die Nachricht zur Generierung von Routen
* @return das Verhalten des Verteilzentrums
*/
private Behavior<Message> onGenerateRoutes(GenerateRoutes msg) {
List<ActorRef<Customer.Message>> customers = msg.getCustomers();
generateRoutes(customers);
return this;
}
/**
* Generiert Routen für Lieferwagen.
*
* @param customers die Liste der Kunden
*/
private void generateRoutes(List<ActorRef<Customer.Message>> customers) {
if (customers == null || customers.isEmpty()) {
getContext().getLog().info("Kundenliste ist leer oder null. Keine Routen generiert.");
@ -135,6 +177,12 @@ public class DistributionCenter extends AbstractBehavior<DistributionCenter.Mess
}
}
/**
* Startet alle Routen für die Lieferwagen.
*
* @param msg die Nachricht zum Starten aller Routen
* @return das Verhalten des Verteilzentrums
*/
private Behavior<Message> onStartAllRoutes(StartAllRoutes msg) {
for (ActorRef<DeliveryCar.Message> deliveryCar : deliveryCars) {
deliveryCar.tell(new DeliveryCar.StartRoute());
@ -142,6 +190,12 @@ public class DistributionCenter extends AbstractBehavior<DistributionCenter.Mess
return this;
}
/**
* Generiert eine zufällige Route aus einer Liste von Kunden.
*
* @param customers die Liste der Kunden
* @return eine zufällige Route
*/
private List<ActorRef<Customer.Message>> generateRandomRoute(List<ActorRef<Customer.Message>> customers) {
List<ActorRef<Customer.Message>> route = new ArrayList<>(customers);
Collections.shuffle(route);

View File

@ -2,20 +2,36 @@ package com.example;
import akka.actor.typed.ActorRef;
/**
* Paket class that represents a package in the system.
*/
public class Paket {
// Inhalt des Pakets
String inhalt;
// Absender des Pakets
String absender;
// Empfänger des Pakets
ActorRef<Customer.Message> empfaenger;
// Konstruktor, der nur den Inhalt annimmt
/**
* Constructor that initializes a package with only the content.
* The sender and recipient are optional and can be set later.
*
* @param inhalt the content of the package
*/
Paket(String inhalt) {
this.inhalt = inhalt;
this.absender = null; // Absender und Empfänger können optional sein
this.empfaenger = null;
this.absender = null; // Absender ist optional
this.empfaenger = null; // Empfänger ist optional
}
// Konstruktor mit allen Parametern
/**
* Constructor that initializes a package with content, sender, and recipient.
*
* @param inhalt the content of the package
* @param absender the sender of the package
* @param empfaenger the recipient of the package
*/
Paket(String inhalt, String absender, ActorRef<Customer.Message> empfaenger) {
this.inhalt = inhalt;
this.absender = absender;