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 0cd7922f2780385e4b71d798e5266cdb7d5c2c82..0191f526bde1696095e017499625e7a22e671c7f 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 f3c76cef85627fb6c7f25a88877b27e874309b2a..d9b1add4f671f1a9e2ed82bffe545330559ac4ae 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 0000000000000000000000000000000000000000..0ed2f17bc9fd45c4b799994856c433c0a1854760 --- /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 0000000000000000000000000000000000000000..3eccef3df42903399fb43426a3154e60bc8034c7 --- /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 0000000000000000000000000000000000000000..5c3d45d3a5129e1c275d7c5d3f60d1bb4b8ff1c6 --- /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 0000000000000000000000000000000000000000..789553b7b062474df906d6432f495ff99a0dc060 --- /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 0000000000000000000000000000000000000000..72c0061d4f83a13bf4f994935606a3b19923b5a9 --- /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 0000000000000000000000000000000000000000..07fd8efa33d272e117f610e40aac675b7d5eb425 --- /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 0000000000000000000000000000000000000000..cb5927302034cf20ba28c14114a1f50b50619076 --- /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 0000000000000000000000000000000000000000..5fb6d2d9c340a516160a28fa5d15fce3ecb2c616 --- /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 0000000000000000000000000000000000000000..d2929ca45be9a793f86f6f7ff5a0d3f469216be2 --- /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 Binary files a/website/assignments/bewertungsbogen.xlsx and b/website/assignments/bewertungsbogen.xlsx differ diff --git a/website/concurrency.html b/website/concurrency.html new file mode 100644 index 0000000000000000000000000000000000000000..65094a3ec77bee007e0b476e365881e49d993059 --- /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