diff --git a/src/pp.11.01-FindWords/README.md b/src/pp.11.01-FindWords/README.md new file mode 100644 index 0000000..f8a4db0 --- /dev/null +++ b/src/pp.11.01-FindWords/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in einigen wenigen Textdateien" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-01-FindWords.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-einigen-wenigen-textdateien) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html) diff --git a/src/pp.11.01-FindWords/justfile b/src/pp.11.01-FindWords/justfile new file mode 100644 index 0000000..6c0be50 --- /dev/null +++ b/src/pp.11.01-FindWords/justfile @@ -0,0 +1,17 @@ +# Justfile (https://just.systems/) for starting Maven standard targets + +default: + just exec pp.Main "" + +exec class args: compile + mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}} +clean: + mvn clean +compile: + mvn compile +test: compile + mvn test +javadoc: + mvn javadoc:javadoc +package: + mvn package diff --git a/src/pp.11.01-FindWords/pom.xml b/src/pp.11.01-FindWords/pom.xml new file mode 100644 index 0000000..f72ca37 --- /dev/null +++ b/src/pp.11.01-FindWords/pom.xml @@ -0,0 +1,76 @@ + + 4.0.0 + pp + pp.11.01-FindWords + 1.0-SNAPSHOT + jar + + pp.Main + 16 + edge-SNAPSHOT + UTF-8 + + + + com.typesafe.akka + akka-actor_3 + 2.8.5 + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile exec:java + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + + private + en_US + + + + + diff --git a/src/pp.11.01-FindWords/src/main/java/pp/ListenerActor.java b/src/pp.11.01-FindWords/src/main/java/pp/ListenerActor.java new file mode 100644 index 0000000..b0f89b0 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/ListenerActor.java @@ -0,0 +1,4 @@ +package pp; + +public class ListenerActor { +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/Main.java b/src/pp.11.01-FindWords/src/main/java/pp/Main.java new file mode 100644 index 0000000..f25ba7b --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/Main.java @@ -0,0 +1,20 @@ +package pp; + +import java.util.Arrays; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import pp.messages.FindMsg; + +public class Main { + + public static void main(String... args) { + var system = ActorSystem.create(); + var master = system.actorOf(Props.create(MasterActor.class)); + String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt", "src/main/resources/test4.txt" }; + var msg = new FindMsg(Arrays.asList(files), "Erlang"); + master.tell(msg, ActorRef.noSender()); + } + +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/MasterActor.java b/src/pp.11.01-FindWords/src/main/java/pp/MasterActor.java new file mode 100644 index 0000000..e3e5b31 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/MasterActor.java @@ -0,0 +1,43 @@ +package pp; + +import java.util.ArrayList; +import java.util.List; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import pp.messages.FindMsg; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; + +public class MasterActor extends AbstractActor { + private int numOfChild; + private final List result = new ArrayList<>(); + private ActorRef listener; + + public MasterActor() { + // TODO Auto-generated constructor stub + } + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(FindMsg.class, this::handleFindMsg) // + .match(ResultMsg.class, this::handleResultMsg) // + .build(); + } + + private void handleFindMsg(FindMsg msg) { + // TODO ausformulieren + } + + private void handleResultMsg(ResultMsg msg) { + getSender().tell(new PleaseCleanupAndStop(), getSelf()); + this.numOfChild--; + this.result.addAll(msg.result()); + if (this.numOfChild == 0) { + this.listener.tell(new ResultMsg(this.result), getSelf()); + getContext().stop(getSelf()); + } + } + +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/WorkerActor.java b/src/pp.11.01-FindWords/src/main/java/pp/WorkerActor.java new file mode 100644 index 0000000..ff025cf --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/WorkerActor.java @@ -0,0 +1,46 @@ +package pp; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import akka.actor.AbstractActor; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class WorkerActor extends AbstractActor { + private Path path; + private Pattern searchPattern; + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(WorkMsg.class, this::handleWorkMsg) // + .match(PleaseCleanupAndStop.class, + (m) -> getContext().stop(getSelf())) // + .build(); + } + + private void handleWorkMsg(WorkMsg msg) throws IOException { + this.path = Paths.get(msg.filename()); + this.searchPattern = Pattern + .compile(".*\\b" + msg.searchword() + "\\b.*"); + var result = new ArrayList(); + var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8); + var count = 0; + for (var line : lines) { + count++; + if (this.searchPattern.matcher(line).matches()) { + result.add(this.path + " " + count + " : " + line); + } + } + // TODO: Resultat (result) an den MasterActor (Absender der WorkMsg msg) + // zurücksenden + } +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/messages/FindMsg.java b/src/pp.11.01-FindWords/src/main/java/pp/messages/FindMsg.java new file mode 100644 index 0000000..9ab411d --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/messages/FindMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record FindMsg(List filenames, String searchword) { +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/messages/PleaseCleanupAndStop.java b/src/pp.11.01-FindWords/src/main/java/pp/messages/PleaseCleanupAndStop.java new file mode 100644 index 0000000..ab9668e --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/messages/PleaseCleanupAndStop.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record PleaseCleanupAndStop() { +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/messages/ResultMsg.java b/src/pp.11.01-FindWords/src/main/java/pp/messages/ResultMsg.java new file mode 100644 index 0000000..12aa132 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/messages/ResultMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record ResultMsg(List result) { +} diff --git a/src/pp.11.01-FindWords/src/main/java/pp/messages/WorkMsg.java b/src/pp.11.01-FindWords/src/main/java/pp/messages/WorkMsg.java new file mode 100644 index 0000000..7743f97 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/java/pp/messages/WorkMsg.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record WorkMsg(String filename, String searchword) { +} diff --git a/src/pp.11.01-FindWords/src/main/resources/test1.txt b/src/pp.11.01-FindWords/src/main/resources/test1.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test1.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test2.txt b/src/pp.11.01-FindWords/src/main/resources/test2.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test2.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test3.txt b/src/pp.11.01-FindWords/src/main/resources/test3.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test3.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test4.txt b/src/pp.11.01-FindWords/src/main/resources/test4.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test4.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test5.txt b/src/pp.11.01-FindWords/src/main/resources/test5.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test5.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test6.txt b/src/pp.11.01-FindWords/src/main/resources/test6.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test6.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test7.txt b/src/pp.11.01-FindWords/src/main/resources/test7.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test7.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords/src/main/resources/test8.txt b/src/pp.11.01-FindWords/src/main/resources/test8.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords/src/main/resources/test8.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/README.md b/src/pp.11.01-FindWords_solution/README.md new file mode 100644 index 0000000..f8a4db0 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in einigen wenigen Textdateien" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-01-FindWords.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-einigen-wenigen-textdateien) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html) diff --git a/src/pp.11.01-FindWords_solution/justfile b/src/pp.11.01-FindWords_solution/justfile new file mode 100644 index 0000000..6c0be50 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/justfile @@ -0,0 +1,17 @@ +# Justfile (https://just.systems/) for starting Maven standard targets + +default: + just exec pp.Main "" + +exec class args: compile + mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}} +clean: + mvn clean +compile: + mvn compile +test: compile + mvn test +javadoc: + mvn javadoc:javadoc +package: + mvn package diff --git a/src/pp.11.01-FindWords_solution/pom.xml b/src/pp.11.01-FindWords_solution/pom.xml new file mode 100644 index 0000000..08b48cf --- /dev/null +++ b/src/pp.11.01-FindWords_solution/pom.xml @@ -0,0 +1,76 @@ + + 4.0.0 + pp + pp.11.01-FindWords_solution + 1.0-SNAPSHOT + jar + + pp.Main + 16 + edge-SNAPSHOT + UTF-8 + + + + com.typesafe.akka + akka-actor_3 + 2.8.5 + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile exec:java + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + + private + en_US + + + + + diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/ListenerActor.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/ListenerActor.java new file mode 100644 index 0000000..13234b7 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/ListenerActor.java @@ -0,0 +1,16 @@ +package pp; + +import akka.actor.AbstractActor; +import pp.messages.ResultMsg; + +public class ListenerActor extends AbstractActor { + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(ResultMsg.class, (msg) -> { + msg.result().forEach(System.out::println); + getContext().getSystem().terminate(); + }).build(); + } + +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/Main.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/Main.java new file mode 100644 index 0000000..2275ad7 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/Main.java @@ -0,0 +1,20 @@ +package pp; + +import java.util.Arrays; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import pp.messages.FindMsg; + +public class Main { + + public static void main(String... args) { + var system = ActorSystem.create(); + var master = system.actorOf(Props.create(MasterActor.class)); + String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt", "src/main/resources/test4.txt" }; + var msg = new FindMsg(Arrays.asList(files), "Erlang"); + master.tell(msg, ActorRef.noSender()); + } + +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/MasterActor.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/MasterActor.java new file mode 100644 index 0000000..011d940 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/MasterActor.java @@ -0,0 +1,53 @@ +package pp; + +import java.util.ArrayList; +import java.util.List; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import akka.actor.Props; +import pp.messages.FindMsg; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class MasterActor extends AbstractActor { + private int numOfChild; + private final List result = new ArrayList<>(); + private final ActorRef listener; + + public MasterActor() { + this.listener = getContext().actorOf(Props.create(ListenerActor.class)); + } + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(FindMsg.class, this::handleFindMsg) // + .match(ResultMsg.class, this::handleResultMsg) // + .build(); + } + + private void handleFindMsg(FindMsg msg) { + var filenames = msg.filenames(); + var searchword = msg.searchword(); + this.numOfChild = msg.filenames().size(); + for (var filename : filenames) { + var job = new WorkMsg(filename, searchword); + var findActor = getContext() + .actorOf(Props.create(WorkerActor.class)); + findActor.tell(job, getSelf()); + } + + } + + private void handleResultMsg(ResultMsg msg) { + getSender().tell(new PleaseCleanupAndStop(), getSelf()); + this.numOfChild--; + this.result.addAll(msg.result()); + if (this.numOfChild == 0) { + this.listener.tell(new ResultMsg(this.result), getSelf()); + getContext().stop(getSelf()); + } + } +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/WorkerActor.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/WorkerActor.java new file mode 100644 index 0000000..c69edcd --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/WorkerActor.java @@ -0,0 +1,44 @@ +package pp; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.regex.Pattern; + +import akka.actor.AbstractActor; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class WorkerActor extends AbstractActor { + private Path path; + private Pattern searchPattern; + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(WorkMsg.class, this::handleWorkMsg) // + .match(PleaseCleanupAndStop.class, + (m) -> getContext().stop(getSelf())) // + .build(); + } + + private void handleWorkMsg(WorkMsg msg) throws IOException { + this.path = Paths.get(msg.filename()); + this.searchPattern = Pattern + .compile(".*\\b" + msg.searchword() + "\\b.*"); + var result = new ArrayList(); + var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8); + var count = 0; + for (var line : lines) { + count++; + if (this.searchPattern.matcher(line).matches()) { + result.add(this.path + " " + count + " : " + line); + } + } + getSender().tell(new ResultMsg(result), getSelf()); + } +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/FindMsg.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/FindMsg.java new file mode 100644 index 0000000..9ab411d --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/FindMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record FindMsg(List filenames, String searchword) { +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/PleaseCleanupAndStop.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/PleaseCleanupAndStop.java new file mode 100644 index 0000000..ab9668e --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/PleaseCleanupAndStop.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record PleaseCleanupAndStop() { +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/ResultMsg.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/ResultMsg.java new file mode 100644 index 0000000..12aa132 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/ResultMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record ResultMsg(List result) { +} diff --git a/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/WorkMsg.java b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/WorkMsg.java new file mode 100644 index 0000000..7743f97 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/java/pp/messages/WorkMsg.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record WorkMsg(String filename, String searchword) { +} diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test1.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test1.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test1.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test2.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test2.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test2.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test3.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test3.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test3.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test4.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test4.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test4.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test5.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test5.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test5.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test6.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test6.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test6.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test7.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test7.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test7.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.01-FindWords_solution/src/main/resources/test8.txt b/src/pp.11.01-FindWords_solution/src/main/resources/test8.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.01-FindWords_solution/src/main/resources/test8.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/README.md b/src/pp.11.02-RouterFindWords/README.md new file mode 100644 index 0000000..399f826 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in sehr vielen Textdateien mit einem Router" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-02-RouterFindWords.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-sehr-vielen-textdateien-mit-einem-router) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html) diff --git a/src/pp.11.02-RouterFindWords/justfile b/src/pp.11.02-RouterFindWords/justfile new file mode 100644 index 0000000..6c0be50 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/justfile @@ -0,0 +1,17 @@ +# Justfile (https://just.systems/) for starting Maven standard targets + +default: + just exec pp.Main "" + +exec class args: compile + mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}} +clean: + mvn clean +compile: + mvn compile +test: compile + mvn test +javadoc: + mvn javadoc:javadoc +package: + mvn package diff --git a/src/pp.11.02-RouterFindWords/pom.xml b/src/pp.11.02-RouterFindWords/pom.xml new file mode 100644 index 0000000..1043d38 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/pom.xml @@ -0,0 +1,76 @@ + + 4.0.0 + pp + pp.11.02-RouterFindWords + 1.0-SNAPSHOT + jar + + pp.Main + 16 + edge-SNAPSHOT + UTF-8 + + + + com.typesafe.akka + akka-actor_3 + 2.8.5 + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile exec:java + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + + private + en_US + + + + + diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/ListenerActor.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/ListenerActor.java new file mode 100644 index 0000000..13234b7 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/ListenerActor.java @@ -0,0 +1,16 @@ +package pp; + +import akka.actor.AbstractActor; +import pp.messages.ResultMsg; + +public class ListenerActor extends AbstractActor { + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(ResultMsg.class, (msg) -> { + msg.result().forEach(System.out::println); + getContext().getSystem().terminate(); + }).build(); + } + +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/Main.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/Main.java new file mode 100644 index 0000000..9b3ad75 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/Main.java @@ -0,0 +1,23 @@ +package pp; + +import java.util.Arrays; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import pp.messages.FindMsg; + +public class Main { + + public static void main(String... args) { + var system = ActorSystem.create(); + var master = system.actorOf(Props.create(MasterActor.class)); + String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt", + "src/main/resources/test4.txt", + "src/main/resources/test5.txt", "src/main/resources/test6.txt", "src/main/resources/test7.txt", + "src/main/resources/test8.txt" }; + var msg = new FindMsg(Arrays.asList(files), "Erlang"); + master.tell(msg, ActorRef.noSender()); + } + +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/MasterActor.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/MasterActor.java new file mode 100644 index 0000000..6e43b6f --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/MasterActor.java @@ -0,0 +1,54 @@ +package pp; + +import java.util.ArrayList; +import java.util.List; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import akka.actor.Props; +import pp.messages.FindMsg; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class MasterActor extends AbstractActor { + private int numOfChild; + private final List result = new ArrayList<>(); + private final ActorRef listener; + + public MasterActor() { + this.listener = getContext().actorOf(Props.create(ListenerActor.class)); + } + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(FindMsg.class, this::handleFindMsg) // + .match(ResultMsg.class, this::handleResultMsg) // + .build(); + } + + private void handleFindMsg(FindMsg msg) { + var filenames = msg.filenames(); + var searchword = msg.searchword(); + this.numOfChild = msg.filenames().size(); + for (var filename : filenames) { + var job = new WorkMsg(filename, searchword); + var findActor = getContext() + .actorOf(Props.create(WorkerActor.class)); + findActor.tell(job, getSelf()); + } + + } + + private void handleResultMsg(ResultMsg msg) { + getSender().tell(new PleaseCleanupAndStop(), getSelf()); + this.numOfChild--; + this.result.addAll(msg.result()); + if (this.numOfChild == 0) { + this.listener.tell(new ResultMsg(this.result), getSelf()); + getContext().stop(getSelf()); + } + } + +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/WorkerActor.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/WorkerActor.java new file mode 100644 index 0000000..c69edcd --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/WorkerActor.java @@ -0,0 +1,44 @@ +package pp; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.regex.Pattern; + +import akka.actor.AbstractActor; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class WorkerActor extends AbstractActor { + private Path path; + private Pattern searchPattern; + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(WorkMsg.class, this::handleWorkMsg) // + .match(PleaseCleanupAndStop.class, + (m) -> getContext().stop(getSelf())) // + .build(); + } + + private void handleWorkMsg(WorkMsg msg) throws IOException { + this.path = Paths.get(msg.filename()); + this.searchPattern = Pattern + .compile(".*\\b" + msg.searchword() + "\\b.*"); + var result = new ArrayList(); + var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8); + var count = 0; + for (var line : lines) { + count++; + if (this.searchPattern.matcher(line).matches()) { + result.add(this.path + " " + count + " : " + line); + } + } + getSender().tell(new ResultMsg(result), getSelf()); + } +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/FindMsg.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/FindMsg.java new file mode 100644 index 0000000..9ab411d --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/FindMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record FindMsg(List filenames, String searchword) { +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/PleaseCleanupAndStop.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/PleaseCleanupAndStop.java new file mode 100644 index 0000000..ab9668e --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/PleaseCleanupAndStop.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record PleaseCleanupAndStop() { +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/ResultMsg.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/ResultMsg.java new file mode 100644 index 0000000..12aa132 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/ResultMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record ResultMsg(List result) { +} diff --git a/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/WorkMsg.java b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/WorkMsg.java new file mode 100644 index 0000000..7743f97 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/java/pp/messages/WorkMsg.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record WorkMsg(String filename, String searchword) { +} diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test1.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test1.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test1.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test2.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test2.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test2.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test3.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test3.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test3.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test4.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test4.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test4.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test5.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test5.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test5.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test6.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test6.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test6.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test7.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test7.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test7.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords/src/main/resources/test8.txt b/src/pp.11.02-RouterFindWords/src/main/resources/test8.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords/src/main/resources/test8.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/README.md b/src/pp.11.02-RouterFindWords_solution/README.md new file mode 100644 index 0000000..399f826 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in sehr vielen Textdateien mit einem Router" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-02-RouterFindWords.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-sehr-vielen-textdateien-mit-einem-router) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html) diff --git a/src/pp.11.02-RouterFindWords_solution/justfile b/src/pp.11.02-RouterFindWords_solution/justfile new file mode 100644 index 0000000..6c0be50 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/justfile @@ -0,0 +1,17 @@ +# Justfile (https://just.systems/) for starting Maven standard targets + +default: + just exec pp.Main "" + +exec class args: compile + mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}} +clean: + mvn clean +compile: + mvn compile +test: compile + mvn test +javadoc: + mvn javadoc:javadoc +package: + mvn package diff --git a/src/pp.11.02-RouterFindWords_solution/pom.xml b/src/pp.11.02-RouterFindWords_solution/pom.xml new file mode 100644 index 0000000..c1c1129 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/pom.xml @@ -0,0 +1,76 @@ + + 4.0.0 + pp + pp.11.02-RouterFindWords_solution + 1.0-SNAPSHOT + jar + + pp.Main + 16 + edge-SNAPSHOT + UTF-8 + + + + com.typesafe.akka + akka-actor_3 + 2.8.5 + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile exec:java + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + + private + en_US + + + + + diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/ListenerActor.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/ListenerActor.java new file mode 100644 index 0000000..13234b7 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/ListenerActor.java @@ -0,0 +1,16 @@ +package pp; + +import akka.actor.AbstractActor; +import pp.messages.ResultMsg; + +public class ListenerActor extends AbstractActor { + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(ResultMsg.class, (msg) -> { + msg.result().forEach(System.out::println); + getContext().getSystem().terminate(); + }).build(); + } + +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/Main.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/Main.java new file mode 100644 index 0000000..9b3ad75 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/Main.java @@ -0,0 +1,23 @@ +package pp; + +import java.util.Arrays; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import pp.messages.FindMsg; + +public class Main { + + public static void main(String... args) { + var system = ActorSystem.create(); + var master = system.actorOf(Props.create(MasterActor.class)); + String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt", + "src/main/resources/test4.txt", + "src/main/resources/test5.txt", "src/main/resources/test6.txt", "src/main/resources/test7.txt", + "src/main/resources/test8.txt" }; + var msg = new FindMsg(Arrays.asList(files), "Erlang"); + master.tell(msg, ActorRef.noSender()); + } + +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/MasterActor.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/MasterActor.java new file mode 100644 index 0000000..ddd60b6 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/MasterActor.java @@ -0,0 +1,70 @@ +package pp; + +import java.util.ArrayList; +import java.util.List; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import akka.actor.Props; +import akka.routing.ActorRefRoutee; +import akka.routing.RoundRobinRoutingLogic; +import akka.routing.Routee; +import akka.routing.Router; +import pp.messages.FindMsg; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class MasterActor extends AbstractActor { + private int numOfChild; + private final List result = new ArrayList<>(); + private final ActorRef listener; + + private final List routees; + private final Router router; + + private static final int WORKER_NUM = 5; + + public MasterActor() { + this.listener = getContext().actorOf(Props.create(ListenerActor.class)); + this.routees = new ArrayList<>(); + for (var i = 0; i < MasterActor.WORKER_NUM; i++) { + var r = getContext().actorOf(Props.create(WorkerActor.class)); + getContext().watch(r); + this.routees.add(new ActorRefRoutee(r)); + } + this.router = new Router(new RoundRobinRoutingLogic(), this.routees); + } + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(FindMsg.class, this::handleFindMsg) // + .match(ResultMsg.class, this::handleResultMsg) // + .build(); + } + + private void handleFindMsg(FindMsg msg) { + var filenames = msg.filenames(); + var searchword = msg.searchword(); + this.numOfChild = msg.filenames().size(); + for (var filename : filenames) { + var job = new WorkMsg(filename, searchword); + this.router.route(job, getSelf()); + } + + } + + private void handleResultMsg(ResultMsg msg) { + this.numOfChild--; + this.result.addAll(msg.result()); + if (this.numOfChild == 0) { + for (var routee : this.routees) { + routee.send(new PleaseCleanupAndStop(), getSelf()); + } + this.listener.tell(new ResultMsg(this.result), getSelf()); + getContext().stop(getSelf()); + } + } + +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/WorkerActor.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/WorkerActor.java new file mode 100644 index 0000000..c69edcd --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/WorkerActor.java @@ -0,0 +1,44 @@ +package pp; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.regex.Pattern; + +import akka.actor.AbstractActor; +import pp.messages.PleaseCleanupAndStop; +import pp.messages.ResultMsg; +import pp.messages.WorkMsg; + +public class WorkerActor extends AbstractActor { + private Path path; + private Pattern searchPattern; + + @Override + public Receive createReceive() { + return receiveBuilder() // + .match(WorkMsg.class, this::handleWorkMsg) // + .match(PleaseCleanupAndStop.class, + (m) -> getContext().stop(getSelf())) // + .build(); + } + + private void handleWorkMsg(WorkMsg msg) throws IOException { + this.path = Paths.get(msg.filename()); + this.searchPattern = Pattern + .compile(".*\\b" + msg.searchword() + "\\b.*"); + var result = new ArrayList(); + var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8); + var count = 0; + for (var line : lines) { + count++; + if (this.searchPattern.matcher(line).matches()) { + result.add(this.path + " " + count + " : " + line); + } + } + getSender().tell(new ResultMsg(result), getSelf()); + } +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/FindMsg.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/FindMsg.java new file mode 100644 index 0000000..9ab411d --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/FindMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record FindMsg(List filenames, String searchword) { +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/PleaseCleanupAndStop.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/PleaseCleanupAndStop.java new file mode 100644 index 0000000..ab9668e --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/PleaseCleanupAndStop.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record PleaseCleanupAndStop() { +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/ResultMsg.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/ResultMsg.java new file mode 100644 index 0000000..12aa132 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/ResultMsg.java @@ -0,0 +1,6 @@ +package pp.messages; + +import java.util.List; + +public record ResultMsg(List result) { +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/WorkMsg.java b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/WorkMsg.java new file mode 100644 index 0000000..7743f97 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/java/pp/messages/WorkMsg.java @@ -0,0 +1,4 @@ +package pp.messages; + +public record WorkMsg(String filename, String searchword) { +} diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test1.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test1.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test1.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test2.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test2.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test2.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test3.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test3.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test3.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test4.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test4.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test4.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test5.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test5.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test5.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test6.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test6.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test6.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test7.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test7.txt new file mode 100644 index 0000000..6c165c1 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test7.txt @@ -0,0 +1,4 @@ +Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen. diff --git a/src/pp.11.02-RouterFindWords_solution/src/main/resources/test8.txt b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test8.txt new file mode 100644 index 0000000..2b51d14 --- /dev/null +++ b/src/pp.11.02-RouterFindWords_solution/src/main/resources/test8.txt @@ -0,0 +1,4 @@ +Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet. +Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann. +Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert. +Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.