From 6dd204d542a764d24b4eb71af009c5ab88fa27b6 Mon Sep 17 00:00:00 2001
From: Tobias Jordine <jordine@hdm-stuttgart.de>
Date: Thu, 9 Jun 2022 22:01:21 +0200
Subject: [PATCH] Code Demos Concurrency inkl. Bewertungskriterien

---
 .../vorlesung/clientserver}/EchoServer.java   |   2 +
 .../vorlesung/clientserver}/GreetClient.java  |   2 +
 .../issues/ConcurrentModificationDemo.java    |  27 ++
 .../concurrency/issues/DeadLock.java          |  60 +++
 .../concurrency/issues/LostUpdate.java        |  43 ++
 .../ConcurrentModificationSolutionDemo.java   |  27 ++
 .../solutions/DeadLockSolution.java           |  60 +++
 .../concurrency/solutions/FutureDemo.java     |  53 +++
 .../concurrency/solutions/JavaStreams.java    |  32 ++
 .../solutions/LostUpdateAtomic.java           |  45 ++
 .../solutions/LostUpdateSynchronized.java     |  46 ++
 website/assignments/bewertungsbogen.xlsx      | Bin 19521 -> 19741 bytes
 website/concurrency.html                      | 419 ++++++++++++++++++
 13 files changed, 816 insertions(+)
 rename src/main/java/{ => de/hdm/jordine/vorlesung/clientserver}/EchoServer.java (96%)
 rename src/main/java/{ => de/hdm/jordine/vorlesung/clientserver}/GreetClient.java (96%)
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/ConcurrentModificationDemo.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/DeadLock.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/LostUpdate.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/ConcurrentModificationSolutionDemo.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/DeadLockSolution.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/FutureDemo.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/JavaStreams.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateAtomic.java
 create mode 100644 src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateSynchronized.java
 create mode 100644 website/concurrency.html

diff --git a/src/main/java/EchoServer.java b/src/main/java/de/hdm/jordine/vorlesung/clientserver/EchoServer.java
similarity index 96%
rename from src/main/java/EchoServer.java
rename to src/main/java/de/hdm/jordine/vorlesung/clientserver/EchoServer.java
index 0cd7922..0191f52 100644
--- a/src/main/java/EchoServer.java
+++ b/src/main/java/de/hdm/jordine/vorlesung/clientserver/EchoServer.java
@@ -1,3 +1,5 @@
+package de.hdm.jordine.vorlesung.clientserver;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
diff --git a/src/main/java/GreetClient.java b/src/main/java/de/hdm/jordine/vorlesung/clientserver/GreetClient.java
similarity index 96%
rename from src/main/java/GreetClient.java
rename to src/main/java/de/hdm/jordine/vorlesung/clientserver/GreetClient.java
index f3c76ce..d9b1add 100644
--- a/src/main/java/GreetClient.java
+++ b/src/main/java/de/hdm/jordine/vorlesung/clientserver/GreetClient.java
@@ -1,3 +1,5 @@
+package de.hdm.jordine.vorlesung.clientserver;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/ConcurrentModificationDemo.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/ConcurrentModificationDemo.java
new file mode 100644
index 0000000..0ed2f17
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/ConcurrentModificationDemo.java
@@ -0,0 +1,27 @@
+package de.hdm.jordine.vorlesung.concurrency.issues;
+
+import java.util.*;
+
+//based on https://www.geeksforgeeks.org/difference-traditional-collections-concurrent-collections-java/
+
+public class ConcurrentModificationDemo{
+
+    public static void main(String[] args) throws InterruptedException {
+        Collection<Integer> asyncCollection = new ArrayList<>();
+        Runnable listOperations = () -> {
+            for (int i = 0; i < 100; i++) {
+                asyncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));
+            }
+        };
+
+        Thread thread1 = new Thread(listOperations);
+        Thread thread2 = new Thread(listOperations);
+        thread1.start();
+        thread2.start();
+        thread1.join();
+        thread2.join();
+
+        System.out.println(asyncCollection.size());
+    }
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/DeadLock.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/DeadLock.java
new file mode 100644
index 0000000..3eccef3
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/DeadLock.java
@@ -0,0 +1,60 @@
+package de.hdm.jordine.vorlesung.concurrency.issues;
+
+// based on https://www.tutorialspoint.com/java/java_thread_deadlock.htm
+
+public class DeadLock {
+
+    public static void main(String[] args) {
+
+        Object lock1 = new Object();
+        Object lock2 = new Object();
+
+        Thread t0 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (lock1){
+                    System.out.println("Thread 1 has lock1");
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+
+                    System.out.println("Thread 1 waiting for lock2");
+
+                    synchronized (lock2){
+                        System.out.println("Thread 1 has lock2 and lock1");
+                    }
+                }
+
+            }
+        });
+
+        Thread t1 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (lock2){
+                    System.out.println("Thread 2 has lock2");
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+
+                    System.out.println("Thread 2 waiting for lock1");
+
+                    synchronized (lock1){
+                        System.out.println("Thread 2 has lock1 and lock2");
+                    }
+                }
+            }
+        });
+
+        t0.start();
+        t1.start();
+
+    }
+
+
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/LostUpdate.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/LostUpdate.java
new file mode 100644
index 0000000..5c3d45d
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/issues/LostUpdate.java
@@ -0,0 +1,43 @@
+package de.hdm.jordine.vorlesung.concurrency.issues;
+
+public class LostUpdate {
+
+    private int counter = 0;
+
+    public void increment(){
+        counter++;
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+
+        LostUpdate lu = new LostUpdate();
+
+        Thread t0 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < 10000; i++) {
+                    lu.increment();
+                }
+            }
+        });
+
+        Thread t1 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < 10000; i++) {
+                    lu.increment();
+                }
+            }
+        });
+
+        t0.start();
+        t1.start();
+
+        //t0.join();
+        //t1.join();
+
+        System.out.println("Counter value: " + lu.counter);
+    }
+
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/ConcurrentModificationSolutionDemo.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/ConcurrentModificationSolutionDemo.java
new file mode 100644
index 0000000..789553b
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/ConcurrentModificationSolutionDemo.java
@@ -0,0 +1,27 @@
+package de.hdm.jordine.vorlesung.concurrency.solutions;
+
+import java.util.*;
+
+//based on https://www.baeldung.com/java-synchronized-collections
+
+public class ConcurrentModificationSolutionDemo{
+
+    public static void main(String[] args) throws InterruptedException {
+        Collection<Integer> syncCollection = Collections.synchronizedCollection(new ArrayList<>());
+        Runnable listOperations = () -> {
+            for (int i = 0; i < 100; i++) {
+                syncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));
+            }
+        };
+
+        Thread thread1 = new Thread(listOperations);
+        Thread thread2 = new Thread(listOperations);
+        thread1.start();
+        thread2.start();
+        thread1.join();
+        thread2.join();
+
+        System.out.println(syncCollection.size());
+    }
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/DeadLockSolution.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/DeadLockSolution.java
new file mode 100644
index 0000000..72c0061
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/DeadLockSolution.java
@@ -0,0 +1,60 @@
+package de.hdm.jordine.vorlesung.concurrency.solutions;
+
+// based on https://www.tutorialspoint.com/java/java_thread_deadlock.htm
+
+public class DeadLockSolution {
+
+    public static void main(String[] args) {
+
+        Object lock1 = new Object();
+        Object lock2 = new Object();
+
+        Thread t0 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (lock1){
+                    System.out.println("Thread 1 has lock1");
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+
+                    System.out.println("Thread 1 waiting for lock2");
+
+                    synchronized (lock2){
+                        System.out.println("Thread 1 has lock1 and lock2");
+                    }
+                }
+
+            }
+        });
+
+        Thread t1 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (lock1){
+                    System.out.println("Thread 2 has lock2");
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+
+                    System.out.println("Thread 2 waiting for lock1");
+
+                    synchronized (lock2){
+                        System.out.println("Thread 2 has lock1 and lock2");
+                    }
+                }
+            }
+        });
+
+        t0.start();
+        t1.start();
+
+    }
+
+
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/FutureDemo.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/FutureDemo.java
new file mode 100644
index 0000000..07fd8ef
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/FutureDemo.java
@@ -0,0 +1,53 @@
+package de.hdm.jordine.vorlesung.concurrency.solutions;
+
+import java.util.concurrent.*;
+
+// based on https://www.baeldung.com/java-future
+
+public class FutureDemo {
+
+    private ExecutorService executor;
+
+    public Future<Integer> calculate(Integer input) {
+        executor = Executors.newFixedThreadPool(10);
+        return executor.submit(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                Thread.sleep(1000);
+                return input * input;
+            }
+        });
+    }
+
+    public void shutdownExecutor() throws InterruptedException {
+        executor.shutdown();
+        try {
+            if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+        }
+    }
+
+    public static void main(String[] args) throws ExecutionException, InterruptedException {
+        FutureDemo demo = new FutureDemo();
+        System.out.println("Starting calculation");
+        Future<Integer> result0 = demo.calculate(2);
+        System.out.println("2 x 2 = " + result0.get());
+
+        Future<Integer> result1 = demo.calculate(4);
+        while (!result1.isDone()){
+            System.out.println("calculating...");
+            Thread.sleep(300);
+        }
+
+        System.out.println("4 x 4 = " + result1.get());
+
+        demo.shutdownExecutor();
+        System.out.println("exit");
+        System.exit(0);
+    }
+
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/JavaStreams.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/JavaStreams.java
new file mode 100644
index 0000000..cb59273
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/JavaStreams.java
@@ -0,0 +1,32 @@
+package de.hdm.jordine.vorlesung.concurrency.solutions;
+
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+//based on https://mkyong.com/java8/java-8-parallel-streams-examples/
+public class JavaStreams {
+
+    public static boolean isPrime(int number) {
+        if (number <= 1) return false;
+        return !IntStream.rangeClosed(2, number / 2).anyMatch(i -> number % i == 0);
+    }
+
+    public static void main(String[] args) {
+
+        long start = System.currentTimeMillis();
+
+        long count = Stream.iterate(0, n -> n + 1)
+                .limit(1_000_000)
+                .parallel()
+                .filter(JavaStreams::isPrime)
+                .peek(x -> System.out.format("%s\t", x))
+                .count();
+
+        long end = System.currentTimeMillis();
+
+        long duration = end - start;
+
+        System.out.println("\n\nDuration: " + duration/1000.0);
+    }
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateAtomic.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateAtomic.java
new file mode 100644
index 0000000..5fb6d2d
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateAtomic.java
@@ -0,0 +1,45 @@
+package de.hdm.jordine.vorlesung.concurrency.solutions;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class LostUpdateAtomic {
+
+    private AtomicInteger counter = new AtomicInteger(0);
+
+    public void increment(){
+        counter.incrementAndGet();
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+
+        LostUpdateAtomic lu = new LostUpdateAtomic();
+
+        Thread t0 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < 10000; i++) {
+                    lu.increment();
+                }
+            }
+        });
+
+        Thread t1 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < 10000; i++) {
+                    lu.increment();
+                }
+            }
+        });
+
+        t0.start();
+        t1.start();
+
+        t0.join();
+        t1.join();
+
+        System.out.println("Counter value: " + lu.counter.get());
+    }
+
+
+}
diff --git a/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateSynchronized.java b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateSynchronized.java
new file mode 100644
index 0000000..d2929ca
--- /dev/null
+++ b/src/main/java/de/hdm/jordine/vorlesung/concurrency/solutions/LostUpdateSynchronized.java
@@ -0,0 +1,46 @@
+package de.hdm.jordine.vorlesung.concurrency.solutions;
+
+public class LostUpdateSynchronized {
+
+    private int counter = 0;
+
+    public void increment(){
+        counter++;
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+
+        Object monitor0 = new Object();
+        Object monitor1 = new Object();
+
+        LostUpdateSynchronized lu = new LostUpdateSynchronized();
+
+        Thread t0 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < 10000; i++) {
+                    lu.increment();
+                }
+            }
+        });
+
+        Thread t1 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < 10000; i++) {
+                    lu.increment();
+                }
+            }
+        });
+
+        t0.start();
+        t1.start();
+
+        //t0.join();
+        //t1.join();
+
+        System.out.println("Counter value: " + lu.counter);
+    }
+
+
+}
diff --git a/website/assignments/bewertungsbogen.xlsx b/website/assignments/bewertungsbogen.xlsx
index 1280b71ec19b6063d00fa9d930e77be9327a9ce1..1936851b814da32e84308bccbb79fd9641006984 100644
GIT binary patch
delta 6166
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
J)&FzsKLD#ll7IjJ

delta 5953
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

diff --git a/website/concurrency.html b/website/concurrency.html
new file mode 100644
index 0000000..65094a3
--- /dev/null
+++ b/website/concurrency.html
@@ -0,0 +1,419 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Parallele Programmierung</title>
+    <meta charset="utf-8">
+      <link href="css/hdm.css" rel="stylesheet"></link>
+      <style>
+          /* yanone-kaffeesatz-regular - latin */
+          @font-face {
+              font-family: 'Yanone Kaffeesatz';
+              font-style: normal;
+              font-weight: 400;
+              src: url('fonts/yanone-kaffeesatz-v22-latin-regular.eot'); /* IE9 Compat Modes */
+              src: local(''),
+              url('fonts/yanone-kaffeesatz-v22-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
+              url('fonts/yanone-kaffeesatz-v22-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
+              url('fonts/yanone-kaffeesatz-v22-latin-regular.woff') format('woff'), /* Modern Browsers */
+              url('fonts/yanone-kaffeesatz-v22-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
+              url('fonts/yanone-kaffeesatz-v22-latin-regular.svg#YanoneKaffeesatz') format('svg'); /* Legacy iOS */
+          }
+          /* noto-serif-regular - latin */
+          @font-face {
+              font-family: 'Noto Serif';
+              font-style: normal;
+              font-weight: 400;
+              src: url('fonts/noto-serif-v20-latin-regular.eot'); /* IE9 Compat Modes */
+              src: local(''),
+              url('fonts/noto-serif-v20-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
+              url('fonts/noto-serif-v20-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
+              url('fonts/noto-serif-v20-latin-regular.woff') format('woff'), /* Modern Browsers */
+              url('fonts/noto-serif-v20-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
+              url('fonts/noto-serif-v20-latin-regular.svg#NotoSerif') format('svg'); /* Legacy iOS */
+          }
+          /* ubuntu-mono-regular - latin */
+          @font-face {
+              font-family: 'Ubuntu Mono';
+              font-style: normal;
+              font-weight: 400;
+              src: url('fonts/ubuntu-mono-v14-latin-regular.eot'); /* IE9 Compat Modes */
+              src: local(''),
+              url('fonts/ubuntu-mono-v14-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
+              url('fonts/ubuntu-mono-v14-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
+              url('fonts/ubuntu-mono-v14-latin-regular.woff') format('woff'), /* Modern Browsers */
+              url('fonts/ubuntu-mono-v14-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
+              url('fonts/ubuntu-mono-v14-latin-regular.svg#UbuntuMono') format('svg'); /* Legacy iOS */
+          }
+          /* ubuntu-mono-italic - latin */
+          @font-face {
+              font-family: 'Ubuntu Mono';
+              font-style: italic;
+              font-weight: 400;
+              src: url('fonts/ubuntu-mono-v14-latin-italic.eot'); /* IE9 Compat Modes */
+              src: local(''),
+              url('fonts/ubuntu-mono-v14-latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
+              url('fonts/ubuntu-mono-v14-latin-italic.woff2') format('woff2'), /* Super Modern Browsers */
+              url('fonts/ubuntu-mono-v14-latin-italic.woff') format('woff'), /* Modern Browsers */
+              url('fonts/ubuntu-mono-v14-latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */
+              url('fonts/ubuntu-mono-v14-latin-italic.svg#UbuntuMono') format('svg'); /* Legacy iOS */
+          }
+          /* ubuntu-mono-700 - latin */
+          @font-face {
+              font-family: 'Ubuntu Mono';
+              font-style: normal;
+              font-weight: 700;
+              src: url('fonts/ubuntu-mono-v14-latin-700.eot'); /* IE9 Compat Modes */
+              src: local(''),
+              url('fonts/ubuntu-mono-v14-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
+              url('fonts/ubuntu-mono-v14-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
+              url('fonts/ubuntu-mono-v14-latin-700.woff') format('woff'), /* Modern Browsers */
+              url('fonts/ubuntu-mono-v14-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */
+              url('fonts/ubuntu-mono-v14-latin-700.svg#UbuntuMono') format('svg'); /* Legacy iOS */
+          }
+
+          body { font-family: 'Noto Serif'; }
+          h1, h2, h3 {
+              font-family: 'Yanone Kaffeesatz';
+              font-weight: normal;
+          }
+          .remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
+      </style>
+  </head>
+  <body>
+    <textarea id="source">
+
+class: center, middle, first
+
+# Software-Entwicklung 3
+
+## Parallele Programmierung
+
+---
+
+# Agenda
+
+1. Recap
+2. Parallele Programmierung
+3. https://www.vogella.com/tutorials/JavaConcurrency/article.html
+4. https://www.baeldung.com/java-concurrency
+
+* Warum wird parallele Programmierung benötigt?
+* Prozesse <-> Threads
+* Amdahls Law
+* Wie funktioniert parallele Programmierung?
+* Wie funktioniert parallele Programmierung in Java?
+  * `Thread`
+  * `Runnable`
+  * `wait()`, `join()`, `notify()`
+  * `volatile`
+  * `Executor`-Framework
+* Probleme bei paralleler Programmierung
+  * `shared state`
+  * Lost Update/Race conditions/Dirty Read
+  * Dead Lock -> https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html 
+* Möglichkeiten, Concurrency-Probleme in Java zu beheben
+  * Locks/Monitor-Objekte/`synchronized`
+  * `Atmoic`-Klassen
+  * `Concurrent`-Collections
+  * `Future`s, `Callable`
+  * Funktionale Programmierung -> Java Streams
+    * Was bedeutet funktionale Programmierung?
+* Was ist Skalierung? Horizontale Skalierung <-> vertikale Skalierung
+
+---
+
+# Recap: Was haben wir in der letzten Vorlesung besprochen?
+
+* SQL
+* NoSQL
+
+> Blick ins [Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022projekt)
+
+---
+class: center, middle
+# Welche Formen der Kommunikationsbeziehungen kennen Sie in der (objektorientierten) Programmierung?
+
+---
+# Kommunikationsbeziehungen
+
+Beispiele:
+
+* lokale Schnittstellen
+    * API (lokal)
+* Remote Schnittstellen
+  * RPC
+  * RESTful-APIs
+  * SOAP-APIs
+  * Messaging-APIs/Event-based APIs
+
+---
+# Gruppierung der Schnittstellenarten
+
+## Synchrone Schnittstellen
+
+## Asynchrone Schnittstellen
+
+---
+# Definition synchrone Schnittstelle
+
+> Der Sender **blockiert** bis vom Empfänger eine Antwort geschickt wurde.
+
+## Beispiele für synchrone Kommunikation
+
+* HTTP
+* SOAP
+* GraphQL
+* RPC (z.B. RMI, gRPC)
+* REST
+
+---
+
+# Ablauf synchrone Schnittstelle (vereinfacht)
+
+## Sender
+1. Verfassen einer Nachricht
+2. Verpacken der Nachricht (_Marshalling_)
+3. Absenden der Nachricht
+4. _Warten auf Antwort_
+5. Empfangen der Antwort-Nachricht
+6. Auspacken der Antwort-Nachricht
+7. Verarbeiten der Antwort-Nachricht
+
+---
+# Ablauf synchrone Schnittstelle (vereinfacht)
+
+## Empfänger
+1. _Warten auf eingehende Nachrichten_
+2. Empfangen der Nachricht
+3. Auspacken der Nachricht
+4. Verarbeiten der Nachricht
+5. Verfassen der Antwort-Nachricht
+6. Verpacken der Antwort-Nachricht
+7. Verschicken der Antwort-Nachricht
+
+---
+# Ablauf synchrone Schnittstelle
+
+**Neu!**
+
+> Blick ins [Vorlesungs-Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung)
+
+---
+# Was ist REST?
+
+> REST: Representational State Transfer
+
+Softwarearchitekturstil
+
+---
+# Grundprinzipien
+
+_nach [Wikipedia, 2022](https://de.wikipedia.org/wiki/Representational_State_Transfer)_
+
+* Client/Server
+* Zustandslosigkeit
+* Caching
+* Einheitliche Schnittstelle
+  * Adressierbarkeit von Ressourcen
+  * Repräsentationen zur Veränderung von Ressourcen
+  * Selbstbeschreibende Nachrichten
+  * „Hypermedia as the Engine of Application State“ (HATEOAS)
+* Mehrschichtige Systeme
+* Code on Demand (optional)
+---
+# REST-URIs
+
+> URI: Uniform Resource Identifier
+
+Mögliche URI-Muster:
+* `<protocol>://<service-name>/<resource-type>/<resource-id>`
+* `<resource-type>/<resource-id>`
+* `<protocol>://<service-name>/<resource-type>/<resource-id>/<resource-details>`
+* `<protocol>://<service-name>/<api-version>/<resource-type>/<resource-id>`
+
+Beispiele:
+* `https://music-mamager.app/songs/112233`
+* `https://music-mamager.app/songs/112233/play`
+* `https://music-mamager.app/songs/112233/artist`
+* `/v3/songs/112233/artist/json`
+
+---
+# REST im Einsatz
+
+* Verwendung auf Basis von HTTP/HTTPS
+* Nutzen der [HTTP-Verben](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
+  * `POST`
+  * `GET`
+  * `DELETE`
+  * `PUT` (entspricht einem Update)
+  * ...
+* Nutzen der HTTP-Status-Codes für Antworten
+  * [Ãœbersicht der HTTP-Status-Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
+
+---
+# REST-APIs mit OpenAPI 3/Swagger
+
+* API-Spezifikation 
+* API-Dokumentation
+* API-Generierung
+* Testumgebung
+
+[Petstore Demo Projekt](https://petstore.swagger.io/)
+
+---
+# REST mit Spring Boot (I)
+
+* Alternative zu `JAX-WS`
+* Maven-Dependency hinzufügen (`spring-boot-starter-web`)
+
+```xml
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-web</artifactId>
+    <version>2.7.0</version>
+    <!-- ... -->
+</dependency>
+```
+* Erstellen einer Klasse, die mit `@RestController` annotiert wird
+* Annotieren der Methoden mit geeigneter HTTP-Verb Annotation (z.B. `@GetMapping`) und zuweisen des Resource-Pfads (z.B. `/songs`)
+* Mapping der URL-Parameter zu Java-Parametern mit der `@RequestParam(value = "name", defaultValue = "Song 2")`
+
+---
+# REST mit Spring Boot (II)
+
+Start der Anwendung:
+
+```java
+@SpringBootApplication
+public class RestServiceApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(RestServiceApplication.class, args);
+	}
+
+}
+```
+---
+# REST mit Spring Boot (III)
+
+_Quelle: ["Building a RESTful Web Service", spring.io, 2022](https://spring.io/guides/gs/rest-service/)_
+
+```java
+package com.example.restservice;
+
+public class Greeting {
+
+	private final long id;
+	private final String content;
+
+	public Greeting(long id, String content) {
+		this.id = id;
+		this.content = content;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public String getContent() {
+		return content;
+	}
+}
+```
+
+---
+# REST mit Spring Boot (IV)
+
+```java
+package com.example.restservice;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class GreetingController {
+
+	private static final String template = "Hello, %s!";
+	private final AtomicLong counter = new AtomicLong();
+
+	@GetMapping("/greeting")
+	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
+		return new Greeting(counter.incrementAndGet(), String.format(template, name));
+	}
+}
+```
+---
+# REST-Demo im Projekt
+
+> Blick ins [Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022projekt)
+
+---
+class: center, middle
+
+# Asynchrone Kommunikationsbeziehungen
+
+---
+# Definition asynchrone Schnittstelle
+
+> Sender **blockiert nicht** bis vom Empfänger eine Antwort geschickt wurde.
+
+## Beispiele asynchrone Kommunikation
+
+* Chats
+* E-Mail
+* Message Broker/Queues (implementierungsabhängig)
+
+---
+# Message Broker
+
+_nach: "Learn Microservices with Spring Boot", Moisés Macero García, apress, 2020, S. 216_
+
+<img alt="Schematische Darstellung Message Broker" src="img/schnittstellen/message_broker.png" width="100%"/>
+
+---
+# Ablauf asynchrone Schnittstelle (vereinfacht)
+
+## Sender
+1. Verfassen einer Nachricht
+2. Verpacken der Nachricht (_Marshalling_)
+3. Absenden der Nachricht
+4. _Weiter im Programmfluss_
+5. _Ggf. Empfangen der Antwort-Nachricht (nach Zeitraum X)_
+6. _Ggf. Auspacken der Antwort-Nachricht_
+7. _Ggf. Verarbeiten der Antwort-Nachricht_
+
+---
+# Ablauf asynchrone Schnittstelle (vereinfacht)
+
+## Empfänger
+1. _Warten auf eingehende Nachrichten_
+2. Empfangen der Nachricht
+3. Auspacken der Nachricht
+4. Verarbeiten der Nachricht
+5. _Ggf. Verfassen der Antwort-Nachricht_
+6. _Ggf. Verpacken der Antwort-Nachricht_
+7. _Ggf. Verschicken der Antwort-Nachricht_
+
+---
+# Backup Themen: Software im Betrieb
+
+* Eventual consistency
+* Monitoring
+* Logging
+* Security
+* Patching
+* Releaseplanung
+* Downtimes
+* Dokumentation/Schulungen
+
+    </textarea>
+    <script src="js/remark.min.js">
+    </script>
+    <script>
+      var slideshow = remark.create();
+    </script>
+  </body>
+</html>
\ No newline at end of file
-- 
GitLab