From 7334686720a0ca86023997d6ee1c164b4fea8d4b Mon Sep 17 00:00:00 2001 From: Sandro Leuchter Date: Mon, 9 Dec 2024 23:11:18 +0100 Subject: [PATCH] initial Kap. 10 --- src/pp.10.00-Exchanger/README.md | 9 ++ src/pp.10.00-Exchanger/pom.xml | 69 ++++++++++++ .../src/main/java/pp/SimpleExchanger.java | 30 +++++ .../src/test/java/pp/ExchangerTest.java | 66 +++++++++++ src/pp.10.01.Rendezvous/README.md | 7 ++ src/pp.10.01.Rendezvous/pom.xml | 72 ++++++++++++ .../src/main/java/pp/Sum.java | 27 +++++ src/pp.10.01.Rendezvous_solution/README.md | 7 ++ src/pp.10.01.Rendezvous_solution/pom.xml | 72 ++++++++++++ .../src/main/java/pp/Sum.java | 56 ++++++++++ src/pp.10.02.Logger/README.md | 7 ++ src/pp.10.02.Logger/pom.xml | 71 ++++++++++++ .../src/main/java/pp/Logging.java | 20 ++++ .../src/main/java/pp/QueuedLogger.java | 67 +++++++++++ .../src/main/java/pp/SimpleLoggerSafe.java | 48 ++++++++ .../src/main/java/pp/SimpleLoggerUnsafe.java | 65 +++++++++++ .../src/main/java/pp/ThreadLocalLogger.java | 37 +++++++ src/pp.10.02.Logger_solution/README.md | 7 ++ src/pp.10.02.Logger_solution/pom.xml | 71 ++++++++++++ .../src/main/java/pp/Logging.java | 20 ++++ .../src/main/java/pp/QueuedLogger.java | 104 ++++++++++++++++++ .../src/main/java/pp/SimpleLoggerSafe.java | 49 +++++++++ .../src/main/java/pp/SimpleLoggerUnsafe.java | 65 +++++++++++ .../src/main/java/pp/ThreadLocalLogger.java | 48 ++++++++ 24 files changed, 1094 insertions(+) create mode 100644 src/pp.10.00-Exchanger/README.md create mode 100644 src/pp.10.00-Exchanger/pom.xml create mode 100644 src/pp.10.00-Exchanger/src/main/java/pp/SimpleExchanger.java create mode 100644 src/pp.10.00-Exchanger/src/test/java/pp/ExchangerTest.java create mode 100644 src/pp.10.01.Rendezvous/README.md create mode 100644 src/pp.10.01.Rendezvous/pom.xml create mode 100644 src/pp.10.01.Rendezvous/src/main/java/pp/Sum.java create mode 100644 src/pp.10.01.Rendezvous_solution/README.md create mode 100644 src/pp.10.01.Rendezvous_solution/pom.xml create mode 100644 src/pp.10.01.Rendezvous_solution/src/main/java/pp/Sum.java create mode 100644 src/pp.10.02.Logger/README.md create mode 100644 src/pp.10.02.Logger/pom.xml create mode 100644 src/pp.10.02.Logger/src/main/java/pp/Logging.java create mode 100644 src/pp.10.02.Logger/src/main/java/pp/QueuedLogger.java create mode 100644 src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerSafe.java create mode 100644 src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerUnsafe.java create mode 100644 src/pp.10.02.Logger/src/main/java/pp/ThreadLocalLogger.java create mode 100644 src/pp.10.02.Logger_solution/README.md create mode 100644 src/pp.10.02.Logger_solution/pom.xml create mode 100644 src/pp.10.02.Logger_solution/src/main/java/pp/Logging.java create mode 100644 src/pp.10.02.Logger_solution/src/main/java/pp/QueuedLogger.java create mode 100644 src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerSafe.java create mode 100644 src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerUnsafe.java create mode 100644 src/pp.10.02.Logger_solution/src/main/java/pp/ThreadLocalLogger.java diff --git a/src/pp.10.00-Exchanger/README.md b/src/pp.10.00-Exchanger/README.md new file mode 100644 index 0000000..b37d990 --- /dev/null +++ b/src/pp.10.00-Exchanger/README.md @@ -0,0 +1,9 @@ +# Laboraufgabe "naive ``Exchanger``-Implementierung" + +Dies hier ist eine naive (und teilweise) Implementierung eines [Exchangers](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Exchanger.html). + +Die reale Implementierung ist weitaus komplexer: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/concurrent/Exchanger.java + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/10-csp.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/i10-csp.html) diff --git a/src/pp.10.00-Exchanger/pom.xml b/src/pp.10.00-Exchanger/pom.xml new file mode 100644 index 0000000..222add8 --- /dev/null +++ b/src/pp.10.00-Exchanger/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + pp + pp.10.00-Exchanger + 0.0.1-SNAPSHOT + + 10 + edge-SNAPSHOT + UTF-8 + + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile test + + + 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 + + + + + \ No newline at end of file diff --git a/src/pp.10.00-Exchanger/src/main/java/pp/SimpleExchanger.java b/src/pp.10.00-Exchanger/src/main/java/pp/SimpleExchanger.java new file mode 100644 index 0000000..c2a33b4 --- /dev/null +++ b/src/pp.10.00-Exchanger/src/main/java/pp/SimpleExchanger.java @@ -0,0 +1,30 @@ +package pp; + +import net.jcip.annotations.ThreadSafe; + +@ThreadSafe +public class SimpleExchanger { + private T left, right; + private Object monitor = new Object(); + + public T exchange(T data) throws InterruptedException { + synchronized (this.monitor) { + if (this.left == null && this.right == null) { + this.left = data; + while (this.right == null) { + this.monitor.wait(); + } + return this.right; + } else { + this.right = data; + this.monitor.notify(); + try { + return this.left; + } finally { + this.left = null; + this.right = null; + } + } + } + } +} diff --git a/src/pp.10.00-Exchanger/src/test/java/pp/ExchangerTest.java b/src/pp.10.00-Exchanger/src/test/java/pp/ExchangerTest.java new file mode 100644 index 0000000..67c5c83 --- /dev/null +++ b/src/pp.10.00-Exchanger/src/test/java/pp/ExchangerTest.java @@ -0,0 +1,66 @@ +package pp; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class ExchangerTest { + final private SimpleExchanger e = new SimpleExchanger<>(); + + @Test + void test1() { + new Thread(() -> { + try { + assertEquals(Integer.valueOf(2), e.exchange(Integer.valueOf(1))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }).start(); + new Thread(() -> { + try { + assertEquals(Integer.valueOf(1), e.exchange(Integer.valueOf(2))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }).start(); + } + + @Test + void test2() { + new Thread(() -> { + try { + Thread.sleep(1000); + assertEquals(Integer.valueOf(3), e.exchange(Integer.valueOf(4))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }).start(); + new Thread(() -> { + try { + assertEquals(Integer.valueOf(4), e.exchange(Integer.valueOf(3))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }).start(); + } + + @Test + void test3() { + new Thread(() -> { + try { + assertEquals(Integer.valueOf(5), e.exchange(Integer.valueOf(6))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }).start(); + new Thread(() -> { + try { + Thread.sleep(1000); + assertEquals(Integer.valueOf(6), e.exchange(Integer.valueOf(5))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }).start(); + } + +} diff --git a/src/pp.10.01.Rendezvous/README.md b/src/pp.10.01.Rendezvous/README.md new file mode 100644 index 0000000..d7dbda6 --- /dev/null +++ b/src/pp.10.01.Rendezvous/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "CSP mit Java-Mitteln" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-01-Rendezvous.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-Solutions.html#laboraufgabe-csp-mit-java-mitteln) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/10-csp.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/i10-csp.html) diff --git a/src/pp.10.01.Rendezvous/pom.xml b/src/pp.10.01.Rendezvous/pom.xml new file mode 100644 index 0000000..4b31f5f --- /dev/null +++ b/src/pp.10.01.Rendezvous/pom.xml @@ -0,0 +1,72 @@ + + 4.0.0 + pp + pp.10.01.Rendezvous + 1.0-SNAPSHOT + jar + + + io.dama.ffi.rendezvous.Sum + 10 + edge-SNAPSHOT + UTF-8 + + + + 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 + + + + + \ No newline at end of file diff --git a/src/pp.10.01.Rendezvous/src/main/java/pp/Sum.java b/src/pp.10.01.Rendezvous/src/main/java/pp/Sum.java new file mode 100644 index 0000000..a600b12 --- /dev/null +++ b/src/pp.10.01.Rendezvous/src/main/java/pp/Sum.java @@ -0,0 +1,27 @@ +package pp; + +/*- + +package main +import "fmt" +func tasker (o, r chan int, d chan bool) { + o <- 1; o <- 2 + fmt.Println (<-r); d <- true +} +func add (o, r chan int) { + r <- ((<-o) + (<-o)) +} +func main () { + operand, result := make(chan int), make(chan int) + done:= make(chan bool) + go tasker (operand, result, done) + go add (operand, result) + <-done +} + + */ + +public class Sum { + public static void main(String... args) { + } +} diff --git a/src/pp.10.01.Rendezvous_solution/README.md b/src/pp.10.01.Rendezvous_solution/README.md new file mode 100644 index 0000000..d7dbda6 --- /dev/null +++ b/src/pp.10.01.Rendezvous_solution/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "CSP mit Java-Mitteln" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-01-Rendezvous.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-Solutions.html#laboraufgabe-csp-mit-java-mitteln) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/10-csp.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/i10-csp.html) diff --git a/src/pp.10.01.Rendezvous_solution/pom.xml b/src/pp.10.01.Rendezvous_solution/pom.xml new file mode 100644 index 0000000..44adadb --- /dev/null +++ b/src/pp.10.01.Rendezvous_solution/pom.xml @@ -0,0 +1,72 @@ + + 4.0.0 + pp + pp.10.01.Rendezvous_solution + 1.0-SNAPSHOT + jar + + + pp.Sum + 10 + edge-SNAPSHOT + UTF-8 + + + + 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 + + + + + \ No newline at end of file diff --git a/src/pp.10.01.Rendezvous_solution/src/main/java/pp/Sum.java b/src/pp.10.01.Rendezvous_solution/src/main/java/pp/Sum.java new file mode 100644 index 0000000..fba5c10 --- /dev/null +++ b/src/pp.10.01.Rendezvous_solution/src/main/java/pp/Sum.java @@ -0,0 +1,56 @@ +package pp; + +/*- + +package main +import "fmt" +func tasker (o, r chan int, d chan bool) { + o <- 1; o <- 2 + fmt.Println (<-r); d <- true +} +func add (o, r chan int) { + r <- ((<-o) + (<-o)) +} +func main () { + operand, result := make(chan int), make(chan int) + done:= make(chan bool) + go tasker (operand, result, done) + go add (operand, result) + <-done +} + + */ + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class Sum { + static void tasker(int x, int y, BlockingQueue o, + BlockingQueue r, BlockingQueue d) { + o.offer(x); + o.offer(y); + try { + System.out.println(r.take()); + d.put(true); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + static void add(BlockingQueue o, BlockingQueue r) { + try { + r.put(o.take() + o.take()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + public static void main(String... args) throws InterruptedException { + var operand = new LinkedBlockingQueue(); + var result = new LinkedBlockingQueue(); + var done = new LinkedBlockingQueue(); + (new Thread(() -> tasker(1, 2, operand, result, done))).start(); + (new Thread(() -> add(operand, result))).start(); + done.take(); + } +} diff --git a/src/pp.10.02.Logger/README.md b/src/pp.10.02.Logger/README.md new file mode 100644 index 0000000..9808e16 --- /dev/null +++ b/src/pp.10.02.Logger/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "Logging in Multi-Threadumgebungen" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-02-Logger.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-Solutions.html#laboraufgabe-logging-in-multi-threadumgebungen) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/10-csp.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/i10-csp.html) diff --git a/src/pp.10.02.Logger/pom.xml b/src/pp.10.02.Logger/pom.xml new file mode 100644 index 0000000..f2de1c5 --- /dev/null +++ b/src/pp.10.02.Logger/pom.xml @@ -0,0 +1,71 @@ + + 4.0.0 + pp + pp.10.02.Logger + 1.0-SNAPSHOT + jar + + + 19 + edge-SNAPSHOT + UTF-8 + + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile + + + 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 + + + + + \ No newline at end of file diff --git a/src/pp.10.02.Logger/src/main/java/pp/Logging.java b/src/pp.10.02.Logger/src/main/java/pp/Logging.java new file mode 100644 index 0000000..2859326 --- /dev/null +++ b/src/pp.10.02.Logger/src/main/java/pp/Logging.java @@ -0,0 +1,20 @@ +package pp; + +import java.io.PrintStream; + +public interface Logging { + public enum Severity { + Debug, Info, Notice, Warning, Error, Critical, Alert, Emergency; + } + + void log(Severity level, String msg); + + void flush(); + + void setPrintStream(PrintStream out); + + void setSeverityLevel(Severity level); + + Severity getSeverityLevel(); + +} diff --git a/src/pp.10.02.Logger/src/main/java/pp/QueuedLogger.java b/src/pp.10.02.Logger/src/main/java/pp/QueuedLogger.java new file mode 100644 index 0000000..eee283c --- /dev/null +++ b/src/pp.10.02.Logger/src/main/java/pp/QueuedLogger.java @@ -0,0 +1,67 @@ +package pp; + +import java.io.PrintStream; + +final class QueuedLogger extends Thread implements Logging { + + private final Logging logger; + + // ... TODO: BlockingQueues deklarieren ... + + public QueuedLogger() { + logger = null; // ... TODO: initialisieren ... + // ... TODO: BlockingQueues initialisieren ... + setDaemon(true); + setPriority(Thread.MIN_PRIORITY); + start(); // hier kein Problem, da Klasse final (s. pp.01.01-Inheritance) + } + + @Override + public void run() { + while (true) { + // ... TODO: BlockingQueues auswerten und loggen ... + } + } + + @Override + public void log(Severity level, String msg) { + switch (level) { + case Debug: + // ... TODO: Blocking Queue befüllen ... + case Info: + // ... TODO: Blocking Queue befüllen ... + case Notice: + // ... TODO: Blocking Queue befüllen ... + case Warning: + // ... TODO: Blocking Queue befüllen ... + case Error: + // ... TODO: Blocking Queue befüllen ... + case Critical: + // ... TODO: Blocking Queue befüllen ... + case Alert: + // ... TODO: Blocking Queue befüllen ... + case Emergency: + // ... TODO: Blocking Queue befüllen ... + } + } + + @Override + public void flush() { + logger.flush(); + } + + @Override + public void setSeverityLevel(Severity level) { + logger.setSeverityLevel(level); + } + + @Override + public Severity getSeverityLevel() { + return logger.getSeverityLevel(); + } + + @Override + public void setPrintStream(PrintStream out) { + logger.setPrintStream(out); + } +} diff --git a/src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerSafe.java b/src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerSafe.java new file mode 100644 index 0000000..968c0c9 --- /dev/null +++ b/src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerSafe.java @@ -0,0 +1,48 @@ +package pp; + +import java.io.PrintStream; + +public class SimpleLoggerSafe implements Logging, AutoCloseable { + public SimpleLoggerSafe() { + // ... TODO ... + } + + public SimpleLoggerSafe(Severity level) { + // ... TODO ... + } + + public SimpleLoggerSafe(Severity level, PrintStream out) { + // ... TODO ... + } + + @Override + public void close() throws Exception { + // ... TODO ... + } + + @Override + public void log(Severity level, String msg) { + // ... TODO ... + } + + @Override + public void flush() { + // ... TODO ... + } + + @Override + public void setSeverityLevel(Severity level) { + // ... TODO ... + } + + @Override + public void setPrintStream(PrintStream out) { + // ... TODO ... + } + + @Override + public Severity getSeverityLevel() { + // ... TODO ... + return null; + } +} diff --git a/src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerUnsafe.java b/src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerUnsafe.java new file mode 100644 index 0000000..4b0b7a5 --- /dev/null +++ b/src/pp.10.02.Logger/src/main/java/pp/SimpleLoggerUnsafe.java @@ -0,0 +1,65 @@ +package pp; + +import java.io.PrintStream; + +public class SimpleLoggerUnsafe implements Logging, AutoCloseable { + private static final int CAPACITY = 1024; + private final StringBuilder log = new StringBuilder(CAPACITY); + private Severity level; + private PrintStream out; + + public SimpleLoggerUnsafe() { + setSeverityLevel(Logging.Severity.Warning); + setPrintStream(System.err); + } + + public SimpleLoggerUnsafe(Severity level) { + this(); + setSeverityLevel(level); + } + + public SimpleLoggerUnsafe(Severity level, PrintStream out) { + this(level); + setPrintStream(out); + } + + @Override + public void log(Severity level, String msg) { + if (this.level.ordinal() <= level.ordinal()) { + if ((this.log.length() + msg.length() // + + System.lineSeparator().length()) >= log.capacity()) { + flush(); + } + this.log.append(msg).append(System.lineSeparator()); + } + } + + @Override + public void flush() { + if (this.log.length() > 0) { + this.out.print(this.log); + this.out.flush(); + this.log.setLength(0); + } + } + + @Override + public void setSeverityLevel(Severity level) { + this.level = level; + } + + @Override + public void setPrintStream(PrintStream out) { + this.out = out; + } + + @Override + public void close() throws Exception { + flush(); + } + + @Override + public Severity getSeverityLevel() { + return this.level; + } +} diff --git a/src/pp.10.02.Logger/src/main/java/pp/ThreadLocalLogger.java b/src/pp.10.02.Logger/src/main/java/pp/ThreadLocalLogger.java new file mode 100644 index 0000000..d298d51 --- /dev/null +++ b/src/pp.10.02.Logger/src/main/java/pp/ThreadLocalLogger.java @@ -0,0 +1,37 @@ +package pp; + +import java.io.PrintStream; + +public class ThreadLocalLogger implements Logging { + + private ThreadLocal logger = ThreadLocal.withInitial(() -> { + // hier programmieren und ein ThreadLocal statt null + // zurückgeben + return null; + }); + + @Override + public void log(Severity level, String msg) { + logger.get().log(level, msg); + } + + @Override + public void flush() { + logger.get().flush(); + } + + @Override + public void setSeverityLevel(Severity level) { + logger.get().setSeverityLevel(level); + } + + @Override + public Severity getSeverityLevel() { + return logger.get().getSeverityLevel(); + } + + @Override + public void setPrintStream(PrintStream out) { + logger.get().setPrintStream(out); + } +} \ No newline at end of file diff --git a/src/pp.10.02.Logger_solution/README.md b/src/pp.10.02.Logger_solution/README.md new file mode 100644 index 0000000..9808e16 --- /dev/null +++ b/src/pp.10.02.Logger_solution/README.md @@ -0,0 +1,7 @@ +# Laboraufgabe "Logging in Multi-Threadumgebungen" +- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-02-Logger.html) +- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/10-Solutions.html#laboraufgabe-logging-in-multi-threadumgebungen) + +# Materialien +- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/10-csp.html) +- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/i10-csp.html) diff --git a/src/pp.10.02.Logger_solution/pom.xml b/src/pp.10.02.Logger_solution/pom.xml new file mode 100644 index 0000000..f509b40 --- /dev/null +++ b/src/pp.10.02.Logger_solution/pom.xml @@ -0,0 +1,71 @@ + + 4.0.0 + pp + pp.10.02.Logger_solution + 1.0-SNAPSHOT + jar + + + 19 + edge-SNAPSHOT + UTF-8 + + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + clean compile + + + 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 + + + + + \ No newline at end of file diff --git a/src/pp.10.02.Logger_solution/src/main/java/pp/Logging.java b/src/pp.10.02.Logger_solution/src/main/java/pp/Logging.java new file mode 100644 index 0000000..2859326 --- /dev/null +++ b/src/pp.10.02.Logger_solution/src/main/java/pp/Logging.java @@ -0,0 +1,20 @@ +package pp; + +import java.io.PrintStream; + +public interface Logging { + public enum Severity { + Debug, Info, Notice, Warning, Error, Critical, Alert, Emergency; + } + + void log(Severity level, String msg); + + void flush(); + + void setPrintStream(PrintStream out); + + void setSeverityLevel(Severity level); + + Severity getSeverityLevel(); + +} diff --git a/src/pp.10.02.Logger_solution/src/main/java/pp/QueuedLogger.java b/src/pp.10.02.Logger_solution/src/main/java/pp/QueuedLogger.java new file mode 100644 index 0000000..c7886d4 --- /dev/null +++ b/src/pp.10.02.Logger_solution/src/main/java/pp/QueuedLogger.java @@ -0,0 +1,104 @@ +package pp; + +import java.io.PrintStream; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +final class QueuedLogger extends Thread implements Logging { + private final Logging logger; + private final BlockingQueue queueDebug; + private final BlockingQueue queueInfo; + private final BlockingQueue queueNotice; + private final BlockingQueue queueWarning; + private final BlockingQueue queueError; + private final BlockingQueue queueCritical; + private final BlockingQueue queueAlert; + private final BlockingQueue queueEmergency; + + public QueuedLogger() { + logger = new SimpleLoggerUnsafe(); + queueDebug = new LinkedBlockingQueue<>(); + queueInfo = new LinkedBlockingQueue<>(); + queueNotice = new LinkedBlockingQueue<>(); + queueWarning = new LinkedBlockingQueue<>(); + queueError = new LinkedBlockingQueue<>(); + queueCritical = new LinkedBlockingQueue<>(); + queueAlert = new LinkedBlockingQueue<>(); + queueEmergency = new LinkedBlockingQueue<>(); + setDaemon(true); + setPriority(Thread.MIN_PRIORITY); + start(); // hier kein Problem, da Klasse final (s. pp.01.01-Inheritance) + } + + @Override + public void run() { + while (true) { + var msg = ""; + if ((msg = this.queueEmergency.poll()) != null) { + logger.log(Severity.Emergency, msg); + } else if ((msg = this.queueAlert.poll()) != null) { + logger.log(Severity.Alert, msg); + } else if ((msg = this.queueCritical.poll()) != null) { + logger.log(Severity.Critical, msg); + } else if ((msg = this.queueError.poll()) != null) { + logger.log(Severity.Error, msg); + } else if ((msg = this.queueWarning.poll()) != null) { + logger.log(Severity.Warning, msg); + } else if ((msg = this.queueNotice.poll()) != null) { + logger.log(Severity.Notice, msg); + } else if ((msg = this.queueInfo.poll()) != null) { + logger.log(Severity.Info, msg); + } else if ((msg = this.queueDebug.poll()) != null) { + logger.log(Severity.Debug, msg); + } + } + } + + @Override + public void log(Severity level, String msg) { + if (logger.getSeverityLevel().ordinal() <= level.ordinal()) { + var success = false; + while (!success) { // falls die jeweilige Queue schon voll ist + // (success == false) nochmal probieren + switch (level) { + case Debug: + success = this.queueDebug.offer(msg); + case Info: + success = this.queueInfo.offer(msg); + case Notice: + success = this.queueNotice.offer(msg); + case Warning: + success = this.queueWarning.offer(msg); + case Error: + success = this.queueError.offer(msg); + case Critical: + success = this.queueCritical.offer(msg); + case Alert: + success = this.queueAlert.offer(msg); + case Emergency: + success = this.queueEmergency.offer(msg); + } + } + } + } + + @Override + public void flush() { + logger.flush(); + } + + @Override + public void setSeverityLevel(Severity level) { + logger.setSeverityLevel(level); + } + + @Override + public Severity getSeverityLevel() { + return logger.getSeverityLevel(); + } + + @Override + public void setPrintStream(PrintStream out) { + logger.setPrintStream(out); + } +} diff --git a/src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerSafe.java b/src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerSafe.java new file mode 100644 index 0000000..5b4769a --- /dev/null +++ b/src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerSafe.java @@ -0,0 +1,49 @@ +package pp; + +import java.io.PrintStream; + +public class SimpleLoggerSafe extends SimpleLoggerUnsafe + implements Logging, AutoCloseable { + + public SimpleLoggerSafe() { + super(); + } + + public SimpleLoggerSafe(Severity level) { + super(level); + } + + public SimpleLoggerSafe(Severity level, PrintStream out) { + super(level, out); + } + + @Override + public synchronized void log(Severity level, String msg) { + super.log(level, msg); + } + + @Override + public synchronized void flush() { + super.flush(); + } + + @Override + public synchronized void setSeverityLevel(Severity level) { + super.setSeverityLevel(level); + } + + @Override + public synchronized void setPrintStream(PrintStream out) { + super.setPrintStream(out); + } + + @Override + public synchronized void close() throws Exception { + super.close(); + } + + @Override + public synchronized Severity getSeverityLevel() { + return super.getSeverityLevel(); + } +} diff --git a/src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerUnsafe.java b/src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerUnsafe.java new file mode 100644 index 0000000..4b0b7a5 --- /dev/null +++ b/src/pp.10.02.Logger_solution/src/main/java/pp/SimpleLoggerUnsafe.java @@ -0,0 +1,65 @@ +package pp; + +import java.io.PrintStream; + +public class SimpleLoggerUnsafe implements Logging, AutoCloseable { + private static final int CAPACITY = 1024; + private final StringBuilder log = new StringBuilder(CAPACITY); + private Severity level; + private PrintStream out; + + public SimpleLoggerUnsafe() { + setSeverityLevel(Logging.Severity.Warning); + setPrintStream(System.err); + } + + public SimpleLoggerUnsafe(Severity level) { + this(); + setSeverityLevel(level); + } + + public SimpleLoggerUnsafe(Severity level, PrintStream out) { + this(level); + setPrintStream(out); + } + + @Override + public void log(Severity level, String msg) { + if (this.level.ordinal() <= level.ordinal()) { + if ((this.log.length() + msg.length() // + + System.lineSeparator().length()) >= log.capacity()) { + flush(); + } + this.log.append(msg).append(System.lineSeparator()); + } + } + + @Override + public void flush() { + if (this.log.length() > 0) { + this.out.print(this.log); + this.out.flush(); + this.log.setLength(0); + } + } + + @Override + public void setSeverityLevel(Severity level) { + this.level = level; + } + + @Override + public void setPrintStream(PrintStream out) { + this.out = out; + } + + @Override + public void close() throws Exception { + flush(); + } + + @Override + public Severity getSeverityLevel() { + return this.level; + } +} diff --git a/src/pp.10.02.Logger_solution/src/main/java/pp/ThreadLocalLogger.java b/src/pp.10.02.Logger_solution/src/main/java/pp/ThreadLocalLogger.java new file mode 100644 index 0000000..de21bb4 --- /dev/null +++ b/src/pp.10.02.Logger_solution/src/main/java/pp/ThreadLocalLogger.java @@ -0,0 +1,48 @@ +package pp; + +import java.io.FileNotFoundException; +import java.io.PrintStream; + +import javax.naming.OperationNotSupportedException; + +public class ThreadLocalLogger implements Logging { + + private ThreadLocal logger = ThreadLocal.withInitial(() -> { + PrintStream out = null; + try { + // jeder Thread bekommt garantiert seinen eigenen PrintStream + out = new PrintStream(Thread.currentThread().threadId() + ".log"); + } catch (FileNotFoundException e) { + // Abbruch mit Runtime statt Checked Exception: + throw new RuntimeException(e); + } + return new SimpleLoggerUnsafe(Logging.Severity.Warning, out); + }); + + @Override + public void log(Severity level, String msg) { + logger.get().log(level, msg); + } + + @Override + public void flush() { + logger.get().flush(); + } + + @Override + public void setSeverityLevel(Severity level) { + logger.get().setSeverityLevel(level); + } + + @Override + public Severity getSeverityLevel() { + return logger.get().getSeverityLevel(); + } + + @Override + public void setPrintStream(PrintStream out) { + // Threads könnten denselben PrintStream verwenden. Damit das nicht + // passiert, wird diese Methode "abgeschaltet". + throw new RuntimeException(new OperationNotSupportedException()); + } +}