Merge branch 'eugenp:master' into master

This commit is contained in:
Wynn Teo 2024-03-27 11:51:37 +08:00 committed by GitHub
commit 67f5f92133
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
346 changed files with 3876 additions and 437 deletions

View File

@ -12,4 +12,6 @@
- [Count the Number of Unique Digits in an Integer using Java](https://www.baeldung.com/java-int-count-unique-digits)
- [Generate Juggler Sequence in Java](https://www.baeldung.com/java-generate-juggler-sequence)
- [Finding the Parent of a Node in a Binary Search Tree with Java](https://www.baeldung.com/java-find-parent-node-binary-search-tree)
- [Check if a Number Is a Happy Number in Java](https://www.baeldung.com/java-happy-sad-number-test)
- [Find the Largest Number Possible After Removing k Digits of a Number](https://www.baeldung.com/java-find-largest-number-remove-k-digits)
- More articles: [[<-- prev]](/algorithms-miscellaneous-6)

View File

@ -0,0 +1,82 @@
package com.baeldung.algorithms.happynumber;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
class HappyNumberDecider {
public static boolean isHappyNumber(int n) {
Set<Integer> checkedNumbers = new HashSet<>();
while (true) {
n = sumDigitsSquare(n);
if (n == 1) {
return true;
}
if (checkedNumbers.contains(n)) {
return false;
}
checkedNumbers.add(n);
}
}
public static boolean isHappyNumberFloyd(int n) {
int slow = n;
int fast = n;
do {
slow = sumDigitsSquare(slow);
fast = sumDigitsSquare(sumDigitsSquare(fast));
} while (slow != fast);
return slow == 1;
}
private static int sumDigitsSquare(int n) {
int squareSum = 0;
while (n != 0) {
squareSum += (n % 10) * (n % 10);
n /= 10;
}
return squareSum;
}
}
public class HappyNumberUnitTest {
@Test
void whenUsingIsHappyNumber_thenGetTheExpectedResult() {
assertTrue(HappyNumberDecider.isHappyNumber(7));
assertTrue(HappyNumberDecider.isHappyNumber(10));
assertTrue(HappyNumberDecider.isHappyNumber(13));
assertTrue(HappyNumberDecider.isHappyNumber(19));
assertTrue(HappyNumberDecider.isHappyNumber(23));
assertFalse(HappyNumberDecider.isHappyNumber(4));
assertFalse(HappyNumberDecider.isHappyNumber(6));
assertFalse(HappyNumberDecider.isHappyNumber(11));
assertFalse(HappyNumberDecider.isHappyNumber(15));
assertFalse(HappyNumberDecider.isHappyNumber(20));
}
@Test
void whenUsingIsHappyNumber2_thenGetTheExpectedResult() {
assertTrue(HappyNumberDecider.isHappyNumberFloyd(7));
assertTrue(HappyNumberDecider.isHappyNumberFloyd(10));
assertTrue(HappyNumberDecider.isHappyNumberFloyd(13));
assertTrue(HappyNumberDecider.isHappyNumberFloyd(19));
assertTrue(HappyNumberDecider.isHappyNumberFloyd(23));
assertFalse(HappyNumberDecider.isHappyNumberFloyd(4));
assertFalse(HappyNumberDecider.isHappyNumberFloyd(6));
assertFalse(HappyNumberDecider.isHappyNumberFloyd(11));
assertFalse(HappyNumberDecider.isHappyNumberFloyd(15));
assertFalse(HappyNumberDecider.isHappyNumberFloyd(20));
}
}

View File

@ -6,4 +6,5 @@ This module contains articles about Apache Kafka.
You can build the project from the command line using: *mvn clean install*, or in an IDE.
### Relevant Articles:
- [Commit Offsets in Kafka](https://www.baeldung.com/kafka-commit-offsets)

View File

@ -87,6 +87,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
</plugin>
</plugins>
</build>

View File

@ -13,4 +13,5 @@
- [Format LocalDate to ISO 8601 With T and Z](https://www.baeldung.com/java-format-localdate-iso-8601-t-z)
- [Check if Two Date Ranges Overlap](https://www.baeldung.com/java-check-two-date-ranges-overlap)
- [Difference between ZoneOffset.UTC and ZoneId.of(“UTC”)](https://www.baeldung.com/java-zoneoffset-utc-zoneid-of)
- [Check if a Given Time Lies Between Two Times Regardless of Date](https://www.baeldung.com/java-check-between-two-times)
- [[<-- Prev]](/core-java-modules/core-java-datetime-java8-1)

View File

@ -2,3 +2,4 @@
- [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item)
- [Find the Equilibrium Indexes of an Array in Java](https://www.baeldung.com/java-equilibrium-index-array)
- [Moves Zeros to the End of an Array in Java](https://www.baeldung.com/java-array-sort-move-zeros-end)
- [Finding the Majority Element of an Array in Java](https://www.baeldung.com/java-array-find-majority-element)

View File

@ -4,3 +4,4 @@ This module contains articles about the Java ArrayList collection
### Relevant Articles:
- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/java-arraylist-multiple-object-types)
- [Finding the Peak Elements of a List](https://www.baeldung.com/java-list-find-peak)

View File

@ -0,0 +1,49 @@
package com.baeldung.addtoimmutablelist;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
public class AddElementsToImmutableListUnitTest {
public static <T> List<T> appendAnElement(List<T> immutableList, T element) {
List<T> tmpList = new ArrayList<>(immutableList);
tmpList.add(element);
return Collections.unmodifiableList(tmpList);
}
@SafeVarargs
public static <T> List<T> appendElements(List<T> immutableList, T... elements) {
List<T> tmpList = new ArrayList<>(immutableList);
tmpList.addAll(Arrays.asList(elements));
return Collections.unmodifiableList(tmpList);
}
@Test
void whenCallingAppendAnElement_thenGetExpectedResult() {
List<String> myList = List.of("A", "B", "C", "D", "E");
List<String> expected = List.of("A", "B", "C", "D", "E", "F");
List<String> result = appendAnElement(myList, "F");
assertThat(result).isEqualTo(expected)
.isUnmodifiable();
}
@Test
void whenCallingAppendElements_thenGetExpectedResult() {
List<String> myList = List.of("A", "B", "C", "D", "E");
List<String> expected1 = List.of("A", "B", "C", "D", "E", "F");
List<String> result1 = appendElements(myList, "F");
assertThat(result1).isEqualTo(expected1)
.isUnmodifiable();
List<String> expected2 = List.of("A", "B", "C", "D", "E", "F", "G", "H", "I");
List<String> result2 = appendElements(myList, "F", "G", "H", "I");
assertThat(result2).isEqualTo(expected2)
.isUnmodifiable();
}
}

View File

@ -13,4 +13,5 @@ This module contains articles about Java collections
- [Guide to the Java Queue Interface](https://www.baeldung.com/java-queue)
- [An Introduction to Synchronized Java Collections](https://www.baeldung.com/java-synchronized-collections)
- [Convert an Array of Primitives to a List](https://www.baeldung.com/java-primitive-array-to-list)
- [Adding Elements to a Collection During Iteration](https://www.baeldung.com/java-add-elements-collection)
- More articles: [[next -->]](/core-java-modules/core-java-collections-2)

View File

@ -4,3 +4,4 @@
- [Working with Exceptions in Java CompletableFuture](https://www.baeldung.com/java-exceptions-completablefuture)
- [CountDownLatch vs. Semaphore](https://www.baeldung.com/java-countdownlatch-vs-semaphore)
- [Callbacks in ListenableFuture and CompletableFuture](https://www.baeldung.com/java-callbacks-listenablefuture-completablefuture)
- [Guide to ExecutorService vs. CompletableFuture](https://www.baeldung.com/java-executorservice-vs-completablefuture)

View File

@ -5,3 +5,4 @@ This module contains articles about date operations in Java.
- [Calculate Number of Weekdays Between Two Dates in Java](https://www.baeldung.com/java-count-weekdays-between-two-dates)
- [Convert Long to Date in Java](https://www.baeldung.com/java-long-date-conversion)
- [Convert Date to Unix Timestamp in Java](https://www.baeldung.com/java-convert-date-unix-timestamp)
- [Checking if a Date Object Equals Yesterday](https://www.baeldung.com/java-date-check-yesterday)

View File

@ -0,0 +1,73 @@
package com.baeldung.usinggzipInputstream;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
import static java.util.stream.Collectors.toList;
public class Main {
static String filePath = Objects.requireNonNull(Main.class.getClassLoader().getResource("myFile.gz")).getFile();
public static void main(String[] args) throws IOException {
// Test readGZipFile method
List<String> fileContents = readGZipFile(filePath);
System.out.println("Contents of GZIP file:");
fileContents.forEach(System.out::println);
// Test findInZipFile method
String searchTerm = "Line 1 content";
List<String> foundLines = findInZipFile(filePath, searchTerm);
System.out.println("Lines containing '" + searchTerm + "' in GZIP file:");
foundLines.forEach(System.out::println);
// Test useContentsOfZipFile method
System.out.println("Using contents of GZIP file with consumer:");
useContentsOfZipFile(filePath, linesStream -> {
linesStream.filter(line -> line.length() > 10).forEach(System.out::println);
});
}
public static List<String> readGZipFile(String filePath) throws IOException {
List<String> lines = new ArrayList<>();
try (InputStream inputStream = new FileInputStream(filePath);
GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
InputStreamReader inputStreamReader = new InputStreamReader(gzipInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
public static List<String> findInZipFile(String filePath, String toFind) throws IOException {
try (InputStream inputStream = new FileInputStream(filePath);
GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
InputStreamReader inputStreamReader = new InputStreamReader(gzipInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
return bufferedReader.lines().filter(line -> line.contains(toFind)).collect(toList());
}
}
public static void useContentsOfZipFile(String filePath, Consumer<Stream<String>> consumer) throws IOException {
try (InputStream inputStream = new FileInputStream(filePath);
GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
InputStreamReader inputStreamReader = new InputStreamReader(gzipInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
consumer.accept(bufferedReader.lines());
}
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.usinggzipInputstream;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
public class ReadingGZIPUsingGZIPInputStreamUnitTest {
String testFilePath = Objects.requireNonNull(ReadingGZIPUsingGZIPInputStreamUnitTest.class.getClassLoader().getResource("myFile.gz")).getFile();
List<String> expectedFilteredLines = Arrays.asList("Line 1 content", "Line 2 content", "Line 3 content");
@Test
void givenGZFile_whenUsingGZIPInputStream_thenReadLines() throws IOException {
try (Stream<String> lines = Main.readGZipFile(testFilePath).stream()) {
List<String> result = lines
.filter(expectedFilteredLines::contains)
.collect(Collectors.toList());
assertEquals(expectedFilteredLines, result);
}
}
@Test
void givenGZFile_whenUsingtestFindInZipFile_thenReadLines() throws IOException {
String toFind = "Line 1 content";
List<String> result = Main.findInZipFile(testFilePath, toFind);
assertEquals("Line 1 content", result.get(0));
}
@Test
void givenGZFile_whenUsingContentsOfZipFile_thenReadLines() throws IOException {
AtomicInteger count = new AtomicInteger(0);
Main.useContentsOfZipFile(testFilePath, linesStream -> {
linesStream.filter(line -> line.length() > 10).forEach(line -> count.incrementAndGet());
});
assertEquals(3, count.get());
}
}

View File

@ -96,4 +96,5 @@
<properties>
<junit-jupiter-version>5.9.3</junit-jupiter-version>
</properties>
</project>
</project>

View File

@ -0,0 +1,39 @@
package com.baeldung.inputstreamreader;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
public class InputStreamReaderUnitTest {
@Test
public void givenAStringWrittenToAFile_whenReadByInputStreamReader_thenShouldMatchWhenRead(@TempDir Path tempDir) throws IOException {
String sampleTxt = "Good day. This is just a test. Good bye.";
Path sampleOut = tempDir.resolve("sample-out.txt");
List<String> lines = Arrays.asList(sampleTxt);
Files.write(sampleOut, lines);
String absolutePath = String.valueOf(sampleOut.toAbsolutePath());
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(absolutePath), StandardCharsets.UTF_8)) {
boolean isMatched = false;
int b;
StringBuilder sb = new StringBuilder();
while ((b = reader.read()) != -1) {
sb.append((char) b);
if (sb.toString().contains(sampleTxt)) {
isMatched = true;
break;
}
}
assertThat(isMatched).isTrue();
}
}
}

View File

@ -1,3 +1,4 @@
=========
### Relevant articles:
- [Calculate Percentiles in Java](https://www.baeldung.com/java-compute-percentiles)

View File

@ -0,0 +1,26 @@
package com.baeldung.constructorversussettermethod;
public class Product {
private String name;
private double price;
private String category;
public Product(String name, double price, String category) {
this.name = name;
this.price = price;
this.category = category;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public String getCategory() {
return category;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.constructorversussettermethod;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
if (username.matches("[a-zA-Z0-9_]+")) {
this.username = username;
} else {
throw new IllegalArgumentException("Invalid username format");
}
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
if (password.length() >= 8) {
this.password = password;
} else {
throw new IllegalArgumentException("Password must be at least 8 characters long");
}
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.constructorversussettermethod;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ConstructorsVersusSetterMethodsUnitTest {
@Test
public void givenNewUser_whenSettingUsername_thenUsernameIsSet() {
User user = new User();
user.setUsername("john_doe");
assertEquals("john_doe", user.getUsername());
}
@Test
public void givenNewUser_whenSettingPassword_thenPasswordIsSet() {
User user = new User();
user.setPassword("strongPassword123");
assertEquals("strongPassword123", user.getPassword());
}
@Test
public void givenProductDetails_whenCreatingProductWithConstructor_thenProductHasCorrectAttributes() {
Product product = new Product("Smartphone", 599.99, "Electronics");
assertEquals("Smartphone", product.getName());
assertEquals(599.99, product.getPrice(), 0.001);
assertEquals("Electronics", product.getCategory());
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.statementsbeforesuper;
class Child extends Parent {
Child() {
super(); // Or super(10); Correct placements
System.out.println("Child constructor");
additionalInitialization();
// super(); Compilation error: Constructor call must be the first statement in a constructor
}
private void additionalInitialization() {
System.out.println("Additional initialization in Child");
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.statementsbeforesuper;
public class Parent {
public Parent(int id) {
System.out.println("Parametrized Parent constructor");
}
public Parent() {
System.out.println("Parent constructor");
}
}

View File

@ -12,3 +12,4 @@ This module contains articles about Java operators
- [What Does “––>” Mean in Java?](https://www.baeldung.com/java-minus-minus-greaterthan)
- [All the Ways Java Uses the Colon Character](https://www.baeldung.com/java-colon)
- [Convert Infix to Postfix Expressions in Java](https://www.baeldung.com/java-convert-infix-to-postfix-expressions)
- [Representation of Integers at a Bit Level in Java](https://www.baeldung.com/java-integer-bit-representation)

View File

@ -6,7 +6,7 @@ import java.io.IOException;
import org.junit.Test;
public class UrlCheckerUnitTest {
public class UrlCheckerIntegrationTest {
@Test
public void givenValidUrl_WhenUsingHEAD_ThenReturn200() throws IOException {
@ -18,7 +18,7 @@ public class UrlCheckerUnitTest {
@Test
public void givenInvalidIUrl_WhenUsingHEAD_ThenReturn404() throws IOException {
UrlChecker tester = new UrlChecker();
int responseCode = tester.getResponseCodeForURLUsingHead("http://www.example.com/unkownurl");
int responseCode = tester.getResponseCodeForURLUsingHead("http://www.example.com/xyz");
assertEquals(404, responseCode);
}
@ -32,7 +32,7 @@ public class UrlCheckerUnitTest {
@Test
public void givenInvalidIUrl_WhenUsingGET_ThenReturn404() throws IOException {
UrlChecker tester = new UrlChecker();
int responseCode = tester.getResponseCodeForURL("http://www.example.com/unkownurl");
int responseCode = tester.getResponseCodeForURL("http://www.example.com/xyz");
assertEquals(404, responseCode);
}

View File

@ -8,4 +8,5 @@
- [Normalize a URL in Java](https://www.baeldung.com/java-url-normalization)
- [Translating Space Characters in URLEncoder](https://www.baeldung.com/java-urlencoder-translate-space-characters)
- [Creating a Custom URL Connection](https://www.baeldung.com/java-custom-url-connection)
- [[<-- Prev]](/core-java-modules/core-java-networking-3)
- [Obtaining the Last Path Segment of a URI in Java](https://www.baeldung.com/java-uri-get-last-path-segment)
- [[<-- Prev]](/core-java-modules/core-java-networking-3)

View File

@ -13,4 +13,5 @@ This module contains articles about numbers in Java.
- [Binary Numbers in Java](https://www.baeldung.com/java-binary-numbers)
- [Finding the Least Common Multiple in Java](https://www.baeldung.com/java-least-common-multiple)
- [Binary Numbers in Java](https://www.baeldung.com/java-binary-numbers)
- [RGB Representation as an Integer in Java](https://www.baeldung.com/java-rgb-color-representation)
- More articles: [[<-- prev]](../core-java-numbers) [[next -->]](../core-java-numbers-3)

View File

@ -49,7 +49,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<goals>
@ -73,6 +73,7 @@
<source.version>1.8</source.version>
<target.version>1.8</target.version>
<spring.version>5.3.4</spring.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
</properties>
</project>

View File

@ -49,7 +49,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<goals>
@ -73,6 +73,7 @@
<source.version>1.8</source.version>
<target.version>1.8</target.version>
<spring.version>5.3.4</spring.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
</properties>
</project>

View File

@ -0,0 +1,143 @@
package com.baeldung.streams.mapstreamtomap;
import static java.lang.Math.max;
import static java.util.stream.Collectors.flatMapping;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.reducing;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
public class MapStreamToMapUnitTest {
Map<String, Integer> playerMap1 = new HashMap<String, Integer>() {{
put("Kai", 92);
put("Liam", 100);
}};
Map<String, Integer> playerMap2 = new HashMap<String, Integer>() {{
put("Eric", 42);
put("Kevin", 77);
}};
Map<String, Integer> playerMap3 = new HashMap<String, Integer>() {{
put("Saajan", 35);
}};
Map<String, Integer> playerMap4 = new HashMap<String, Integer>() {{
put("Kai", 76);
}};
Map<String, Integer> playerMap5 = new HashMap<String, Integer>() {{
put("Kai", null);
put("Jerry", null);
}};
@Test
void givenMapsStream_whenUsingFlatMapAndToMap_thenMultipleMapsMergedIntoOneMap() {
Map<String, Integer> expectedMap = new HashMap<String, Integer>() {{
put("Saajan", 35);
put("Liam", 100);
put("Kai", 92);
put("Eric", 42);
put("Kevin", 77);
}};
Map<String, Integer> mergedMap = Stream.of(playerMap1, playerMap2, playerMap3)
.flatMap(map -> map.entrySet()
.stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
assertEquals(expectedMap, mergedMap);
}
@Test
void givenMapsWithDuplicateKeys_whenUsingFlatMapAndToMap_thenMultipleMapsMergedIntoOneMap() {
Map<String, Integer> expectedMap = new HashMap<String, Integer>() {{
put("Saajan", 35);
put("Liam", 100);
put("Kai", 92); // max of 76 and 92
put("Eric", 42);
put("Kevin", 77);
}};
assertThrows(IllegalStateException.class, () -> Stream.of(playerMap1, playerMap2, playerMap3, playerMap4)
.flatMap(map -> map.entrySet()
.stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)), "Duplicate key Kai (attempted merging values 92 and 76)");
Map<String, Integer> mergedMap = Stream.of(playerMap1, playerMap2, playerMap3, playerMap4)
.flatMap(map -> map.entrySet()
.stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Integer::max));
assertEquals(expectedMap, mergedMap);
}
private Integer maxInteger(Integer int1, Integer int2) {
if (int1 == null) {
return int2;
}
if (int2 == null) {
return int1;
}
return max(int1, int2);
}
@Test
void givenMapsWithDuplicateKeysAndNullValues_whenUsingFlatMapWithForEach_thenMultipleMapsMergedIntoOneMap() {
Map<String, Integer> expectedMap = new HashMap<String, Integer>() {{
put("Saajan", 35);
put("Liam", 100);
put("Kai", 92); // max of 92, 76, and null
put("Eric", 42);
put("Kevin", 77);
put("Jerry", null);
}};
assertThrows(NullPointerException.class, () -> Stream.of(playerMap1, playerMap2, playerMap3, playerMap4, playerMap5)
.flatMap(map -> map.entrySet()
.stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Integer::max)));
Map<String, Integer> mergedMap = new HashMap<>();
Stream.of(playerMap1, playerMap2, playerMap3, playerMap4, playerMap5)
.flatMap(map -> map.entrySet()
.stream())
.forEach(entry -> {
String k = entry.getKey();
Integer v = entry.getValue();
if (mergedMap.containsKey(k)) {
mergedMap.put(k, maxInteger(mergedMap.get(k), v));
} else {
mergedMap.put(k, v);
}
});
assertEquals(expectedMap, mergedMap);
}
@Test
void givenMapsWithDuplicateKeysAndNullValues_whenUsingReduce_thenMultipleMapsMergedIntoOneMap() {
Map<String, Integer> expectedMap = new HashMap<String, Integer>() {{
put("Saajan", 35);
put("Liam", 100);
put("Kai", 92); // max of 92, 76, and null
put("Eric", 42);
put("Kevin", 77);
put("Jerry", null);
}};
Map<String, Integer> mergedMap = Stream.of(playerMap1, playerMap2, playerMap3, playerMap4, playerMap5)
.flatMap(x -> x.entrySet()
.stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, reducing(null, this::maxInteger))));
assertEquals(expectedMap, mergedMap);
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.UTF8ToISO;
import org.junit.jupiter.api.Test;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import static org.junit.Assert.assertArrayEquals;
public class UTF8ToISOUnitTest {
String string = "âabcd";
byte[] expectedBytes = new byte[]{(byte) 0xE2, 0x61, 0x62, 0x63, 0x64};
@Test
public void givenUtf8String_whenUsingGetByte_thenIsoBytesShouldBeEqual() {
byte[] iso88591bytes = string.getBytes(StandardCharsets.ISO_8859_1);
assertArrayEquals(expectedBytes, iso88591bytes);
}
@Test
public void givenString_whenUsingByteBufferCharBufferConvertToIso_thenBytesShouldBeEqual() {
ByteBuffer inputBuffer = ByteBuffer.wrap(string.getBytes(StandardCharsets.UTF_8));
CharBuffer data = StandardCharsets.UTF_8.decode(inputBuffer);
ByteBuffer outputBuffer = StandardCharsets.ISO_8859_1.encode(data);
byte[] outputData = new byte[outputBuffer.remaining()];
outputBuffer.get(outputData);
assertArrayEquals(expectedBytes, outputData);
}
}

View File

@ -1,7 +0,0 @@
## Dozer
This module contains articles about Dozer
### Relevant Articles:
- [A Guide to Mapping With Dozer](https://www.baeldung.com/dozer)

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>dozer</artifactId>
<name>dozer</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>${dozer.version}</version>
</dependency>
</dependencies>
<properties>
<dozer.version>5.5.1</dozer.version>
</properties>
</project>

View File

@ -1168,7 +1168,7 @@
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
<jib-maven-plugin.version>0.9.11</jib-maven-plugin.version>
<frontend-maven-plugin.version>1.7.6</frontend-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.2</jacoco-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
<scala-maven-plugin.version>3.4.2</scala-maven-plugin.version>
<sonar-maven-plugin.version>3.5.0.1254</sonar-maven-plugin.version>

View File

@ -24,7 +24,7 @@
<hazelcast-hibernate52.version>1.2</hazelcast-hibernate52.version>
<hibernate.version>5.2.8.Final</hibernate.version>
<hikaricp.version>5.1.0</hikaricp.version>
<jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
<java.version>1.8</java.version>
<javassist.version>3.21.0-GA</javassist.version>
<jcache.version>1.0.0</jcache.version>

View File

@ -24,7 +24,7 @@
<hazelcast-hibernate52.version>1.2</hazelcast-hibernate52.version>
<hibernate.version>5.2.8.Final</hibernate.version>
<hikaricp.version>5.1.0</hikaricp.version>
<jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
<javassist.version>3.21.0-GA</javassist.version>
<jcache.version>1.0.0</jcache.version>
<jhipster.server.version>1.1.0</jhipster.server.version>

View File

@ -27,7 +27,7 @@
<hazelcast-hibernate52.version>1.2</hazelcast-hibernate52.version>
<hibernate.version>5.2.8.Final</hibernate.version>
<hikaricp.version>5.1.0</hikaricp.version>
<jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
<javassist.version>3.21.0-GA</javassist.version>
<jcache.version>1.0.0</jcache.version>
<jhipster.server.version>1.1.0</jhipster.server.version>

View File

@ -893,7 +893,7 @@
<gatling.version>2.2.3</gatling.version>
<hibernate.version>5.2.8.Final</hibernate.version>
<hikaricp.version>5.1.0</hikaricp.version>
<jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
<javassist.version>3.21.0-GA</javassist.version>
<jcache.version>1.0.0</jcache.version>
<jhipster.server.version>1.1.0</jhipster.server.version>

View File

@ -0,0 +1,27 @@
package com.baeldung.includenullinjson;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Customer {
@JsonProperty
private final String name;
@JsonProperty
private final String address;
@JsonProperty
private final int age;
public Customer(String name, String address, int age) {
this.name = name;
this.address = address;
this.age = age;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", age=" + age +
'}';
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.includenullinjson;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class IncludeNullValuesInJsonUnitTest {
String expectedJson = "{\"name\":\"John\",\"address\":null,\"age\":25}";
Customer obj = new Customer("John", null, 25);
@Test
public void givenObjectWithNullField_whenJacksonUsed_thenIncludesNullValue() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
String json = mapper.writeValueAsString(obj);
assertEquals(expectedJson, json);
}
@Test
public void givenObjectWithNullField_whenGsonUsed_thenIncludesNullValue() {
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(obj);
assertEquals(expectedJson, json);
}
}

View File

@ -6,6 +6,7 @@ This module contains articles about jsoup.
- [Parsing HTML in Java with Jsoup](https://www.baeldung.com/java-with-jsoup)
- [How to Add Proxy Support to Jsoup?](https://www.baeldung.com/java-jsoup-proxy)
- [Preserving Line Breaks When Using Jsoup](https://www.baeldung.com/jsoup-line-breaks)
- [Parsing HTML Table in Java With Jsoup](https://www.baeldung.com/java-jsoup-parse-html-table)
### Build the Project

View File

@ -6,4 +6,5 @@ This module contains articles about cli libraries.
- [Create a Java Command Line Program with Picocli](https://www.baeldung.com/java-picocli-create-command-line-program)
- [Parsing Command-Line Parameters with JCommander](https://www.baeldung.com/jcommander-parsing-command-line-parameters)
- [Parsing Command-Line Parameters with Airline](https://www.baeldung.com/java-airline)
- [Parsing Command-Line Parameters with Airline](https://www.baeldung.com/java-airline)
- [Intro to the Apache Commons CLI](https://www.baeldung.com/apache-commons-cli)

View File

@ -12,4 +12,5 @@ This module contains articles about libraries for data processing in Java.
- [Introduction to Eclipse Collections](https://www.baeldung.com/eclipse-collections)
- [Introduction to Caffeine](https://www.baeldung.com/java-caching-caffeine)
- [Guide to Using ModelMapper](https://www.baeldung.com/java-modelmapper)
- [A Guide to Mapping With Dozer](https://www.baeldung.com/dozer)
- More articles: [[<-- prev]](/../libraries-data-2)

View File

@ -71,6 +71,17 @@
<artifactId>modelmapper</artifactId>
<version>${org.modelmapper.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>${dozer.version}</version>
</dependency>
</dependencies>
<build>
@ -96,6 +107,7 @@
<caffeine.version>3.1.8</caffeine.version>
<findbugs.version>3.0.2</findbugs.version>
<org.modelmapper.version>3.2.0</org.modelmapper.version>
<dozer.version>5.5.1</dozer.version>
</properties>
</project>

View File

@ -171,7 +171,7 @@ public class DozerIntegrationTest {
configureMapper("dozer_custom_convertor.xml");
String dateTime = "2007-06-26T21:22:39Z";
long timestamp = new Long("1182882159000");
long timestamp = Long.parseLong("1182882159000");
Person3 person = new Person3("Rich", dateTime);
Personne3 person0 = mapper.map(person, Personne3.class);
@ -182,7 +182,7 @@ public class DozerIntegrationTest {
@Test
public void givenSrcAndDestWithDifferentFieldTypes_whenAbleToCustomConvertBidirectionally_thenCorrect() {
long timestamp = new Long("1182882159000");
long timestamp = Long.parseLong("1182882159000");
Personne3 person = new Personne3("Rich", timestamp);
configureMapper("dozer_custom_convertor.xml");

View File

@ -38,7 +38,7 @@
</build>
<properties>
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
</properties>
</project>

View File

@ -84,4 +84,7 @@
</plugins>
</build>
<properties>
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
</properties>
</project>

View File

@ -30,6 +30,7 @@
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<configuration>
<resources combine.children="append">
<resource>

View File

@ -16,6 +16,7 @@
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<configuration>
<resources combine.self="override">
<resource>

View File

@ -0,0 +1,2 @@
### Relevant Articles:
- [Introduction to Redpanda](https://www.baeldung.com/redpanda)

View File

@ -101,6 +101,7 @@
<plugin>
<groupId>io.micronaut.build</groupId>
<artifactId>micronaut-maven-plugin</artifactId>
<version>${micronaut-build.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -154,6 +155,7 @@
<packaging>jar</packaging>
<compiler.plugin.version>3.12.1</compiler.plugin.version>
<micronaut.runtime>netty</micronaut.runtime>
<micronaut-build.version>3.5.4</micronaut-build.version>
<shade.plugin.version>3.2.0</shade.plugin.version>
</properties>

View File

@ -0,0 +1,13 @@
# Saga Pattern Using Orkes Conductor
This is an example project showing how to build event driven applications using [Conductor](https://github.com/conductor-oss/conductor)
# Pre-requisites
1. Docker
2. Running conductor server
**Start the conductor server**
```shell
docker run --init -p 8080:8080 -p 1234:5000 conductoross/conductor-standalone:3.15.0
```

View File

@ -0,0 +1,34 @@
buildscript {
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:3.2.3"
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.3'
id 'io.freefair.lombok' version '8.6'
}
apply plugin: 'io.spring.dependency-management'
group = 'io.orkes.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'io.orkes.conductor:orkes-conductor-client:2.1.0'
implementation 'org.xerial:sqlite-jdbc:3.32.3.3'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,2 @@
rootProject.name = 'conductor-examples-food-delivery'

View File

@ -0,0 +1,28 @@
package io.orkes.example.saga;
import io.orkes.example.saga.dao.BaseDAO;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import lombok.AllArgsConstructor;
@AllArgsConstructor
@SpringBootApplication
@ComponentScan(basePackages = {"io.orkes"})
public class SagaApplication {
private static final BaseDAO db = new BaseDAO("jdbc:sqlite:food_delivery.db");
public static void main(String[] args) {
SpringApplication.run(SagaApplication.class, args);
initDB();
}
public static void initDB() {
db.createTables("orders");
db.createTables("inventory");
db.createTables("payments");
db.createTables("shipments");
}
}

View File

@ -0,0 +1,27 @@
package io.orkes.example.saga.controller;
import io.orkes.example.saga.pojos.FoodDeliveryRequest;
import io.orkes.example.saga.pojos.OrderRequest;
import io.orkes.example.saga.service.WorkflowService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@Slf4j
@AllArgsConstructor
@RestController
public class OrderServiceController {
private final WorkflowService workflowService;
@PostMapping(value = "/triggerFoodDeliveryFlow", produces = "application/json")
public ResponseEntity<Map<String, Object>> triggerFoodDeliveryFlow(@RequestBody FoodDeliveryRequest foodDeliveryRequest) {
return ResponseEntity.ok(workflowService.startFoodDeliveryWorkflow(foodDeliveryRequest));
}
}

View File

@ -0,0 +1,221 @@
package io.orkes.example.saga.dao;
import java.sql.*;
public class BaseDAO {
private String url;
public BaseDAO(String url) {
this.url = url;
}
protected Connection connect() {
Connection conn = null;
try {
conn = DriverManager.getConnection(this.url);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return conn;
}
protected Boolean execute(String sql) {
try (Connection conn = DriverManager.getConnection(this.url); Statement stmt = conn.createStatement()) {
stmt.execute(sql);
} catch (SQLException e) {
System.out.println(e.getMessage());
return false;
}
return true;
}
public void createTables(String service) {
switch (service) {
case "orders":
createOrdersTable();
createOrderDetailsTable();
createCustomerTable();
break;
case "inventory":
createRestaurantsTable();
break;
case "shipments":
createDriversTable();
createShipmentTable();
break;
case "payments":
createPaymentsTable();
break;
default:
System.out.println("Service name not recognized");
}
}
private void createOrdersTable() {
if (!tableExists("orders")) {
String sql = "CREATE TABLE orders (\n"
+ " orderId text PRIMARY KEY,\n"
+ " customerId integer NOT NULL,\n"
+ " restaurantId integer NOT NULL,\n"
+ " deliveryAddress text NOT NULL,\n"
+ " createdAt TIMESTAMP NOT NULL,\n"
+ " status text NOT NULL\n"
+ ");";
execute(sql);
}
}
private void createOrderDetailsTable() {
if (!tableExists("orders_details")) {
String sql = "CREATE TABLE orders_details (\n"
+ " orderId text PRIMARY KEY,\n"
+ " items text NOT NULL,\n"
+ " notes text\n"
+ ");";
execute(sql);
}
}
private void createCustomerTable() {
if (tableExists("customers")) {
return;
}
String sql = "CREATE TABLE customers (\n"
+ " id integer PRIMARY KEY AUTOINCREMENT,\n"
+ " email text NOT NULL,\n"
+ " name text NOT NULL,\n"
+ " contact text\n"
+ ");";
if(execute(sql)) {
seedCustomers();
}
}
private void createRestaurantsTable() {
if (!tableExists("restaurants")) {
String sql = "CREATE TABLE restaurants (\n"
+ " id integer PRIMARY KEY AUTOINCREMENT,\n"
+ " name text NOT NULL,\n"
+ " address text NOT NULL,\n"
+ " contact text NOT NULL\n"
+ ");";
if (execute(sql)) {
seedRestaurants();
}
}
}
private void createPaymentsTable() {
if (tableExists("payments")) {
return;
}
String sql = "CREATE TABLE payments (\n"
+ " paymentId text PRIMARY KEY,\n"
+ " orderId text NOT NULL,\n"
+ " amount number NOT NULL,\n"
+ " method text,\n"
+ " status text,\n"
+ " createdAt TIMESTAMP NOT NULL\n"
+ ");";
execute(sql);
}
private void createDriversTable() {
if (tableExists("drivers")) {
return;
}
String sql = "CREATE TABLE drivers (\n"
+ " id integer PRIMARY KEY AUTOINCREMENT,\n"
+ " name text NOT NULL,\n"
+ " contact text\n"
+ ");";
if(execute(sql)) {
seedDrivers();
}
}
private void createShipmentTable() {
if (tableExists("shipments")) {
return;
}
String sql = "CREATE TABLE shipments (\n"
+ " id integer PRIMARY KEY AUTOINCREMENT,\n"
+ " orderId text NOT NULL,\n"
+ " driverId number NOT NULL,\n"
+ " address text NOT NULL,\n"
+ " instructions text,\n"
+ " status text NOT NULL,\n"
+ " createdAt TIMESTAMP NOT NULL\n"
+ ");";
execute(sql);
}
private void seedCustomers() {
String[] queries = {
"INSERT INTO customers(email, name, contact) VALUES('John Smith','john.smith@example.com','+12126781345');",
"INSERT INTO customers(email, name, contact) VALUES('Mike Ross','mike.ross@example.com','+15466711147');",
"INSERT INTO customers(email, name, contact) VALUES('Martha Williams','martha.williams@example.com','+12790581941');"
};
for (String query : queries) {
execute(query);
}
}
private void seedRestaurants() {
String[] add = {
"5331 Redford Court, Montgomery AL 36116",
"43 West 4th Street, New York NY 10024",
"1693 Alice Court, Annapolis MD 21401"
};
String[] queries = {
"INSERT INTO restaurants(name, address, contact) VALUES('Mikes','+12121231345','" + add[0] + "');",
"INSERT INTO restaurants(name, address, contact) VALUES('Tamarind','+12412311147','" + add[1] + "');",
"INSERT INTO restaurants(name, address, contact) VALUES('Thai Place','+14790981941','" + add[2] + "');",
};
for (String query : queries) {
execute(query);
}
}
private void seedDrivers() {
String[] queries = {
"INSERT INTO drivers(name,contact) VALUES('Wayne Stevens','+12520711467');",
"INSERT INTO drivers(name,contact) VALUES('Jim Willis','+16466281981');",
"INSERT INTO drivers(name,contact) VALUES('Steven Carroll','+12612590430');",
"INSERT INTO drivers(name,contact) VALUES('Tom Cruise','+18659581430');"
};
for (String query : queries) {
execute(query);
}
}
boolean tableExists(String tableName) {
try {
Connection conn = DriverManager.getConnection(this.url);
DatabaseMetaData meta = conn.getMetaData();
ResultSet resultSet = meta.getTables(null, null, tableName, new String[] {"TABLE"});
boolean exists = resultSet.next();
conn.close();
return exists;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return false;
}
}

View File

@ -0,0 +1,33 @@
package io.orkes.example.saga.dao;
import io.orkes.example.saga.pojos.Order;
import io.orkes.example.saga.pojos.Restaurant;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class InventoryDAO extends BaseDAO {
public InventoryDAO(String url) {
super(url);
}
public void readRestaurant(int restaurantId, Restaurant restaurant) {
String sql = "SELECT name, address, contact FROM restaurants WHERE id = ?";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, restaurantId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
restaurant.setName(rs.getString("name"));
restaurant.setAddress(rs.getString("address"));
restaurant.setContact(rs.getString("contact"));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}

View File

@ -0,0 +1,135 @@
package io.orkes.example.saga.dao;
import io.orkes.example.saga.pojos.Customer;
import io.orkes.example.saga.pojos.Order;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Date;
public class OrdersDAO extends BaseDAO {
public OrdersDAO(String url) {
super(url);
}
public String insertOrder(Order order) {
Date date = new Date();
Timestamp nowAsTS = new Timestamp(date.getTime());
String itemsStr = String.join("", order.getOrderDetails().getItems().toString());
String notesStr = null;
if(!order.getOrderDetails().getNotes().isEmpty()) {
notesStr = String.join("", order.getOrderDetails().getNotes().toString());
} else {
notesStr = "";
}
String sql = "INSERT INTO orders(orderId,customerId,restaurantId,deliveryAddress,createdAt,status) VALUES(?,?,?,?,?,?)";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, order.getOrderId());
pstmt.setInt(2, order.getCustomer().getId());
pstmt.setInt(3, order.getRestaurantId());
pstmt.setString(4, order.getDeliveryAddress());
pstmt.setTimestamp(5, nowAsTS);
pstmt.setString(6, order.getStatus().name());
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
return e.getMessage();
}
sql = "INSERT INTO orders_details(orderId,items,notes) VALUES(?,?,?)";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, order.getOrderId());
pstmt.setString(2, itemsStr);
pstmt.setString(3, notesStr);
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
return e.getMessage();
}
return "";
}
public void updateOrder(Order order) {
String sql = "UPDATE orders SET restaurantId=?,deliveryAddress=?,status=? WHERE orderId=?";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, order.getRestaurantId());
pstmt.setString(2, order.getDeliveryAddress());
pstmt.setString(3, order.getStatus().name());
pstmt.setString(4, order.getOrderId());
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public void readOrder(String orderId, Order order) {
String sql = "SELECT orderId, customerId, restaurantId, deliveryAddress, createdAt, status FROM orders WHERE orderId = ?";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, orderId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
order.setOrderId(rs.getString("orderId"));
Customer customer = new Customer();
customer.setId(rs.getInt("customerId"));
order.setCustomer(customer);
order.setRestaurantId(rs.getInt("restaurantId"));
order.setDeliveryAddress(rs.getString("deliveryAddress"));
order.setCreatedAt(rs.getLong("createdAt"));
order.setStatus(Order.Status.valueOf(rs.getString("status")));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public int insertCustomer(Customer customer) {
int id = 0;
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement("SELECT id FROM customers WHERE email = ?")) {
pstmt.setString(1, customer.getEmail());
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
id = rs.getInt("id");
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
if (id > 0) {
return id;
}
String sql = "INSERT INTO customers(email,name,contact) VALUES(?,?,?)";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, customer.getEmail());
pstmt.setString(2, customer.getName());
pstmt.setString(3, customer.getContact());
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement("SELECT id FROM customers WHERE email = ?")) {
pstmt.setString(1, customer.getEmail());
ResultSet rs = pstmt.executeQuery();
id = rs.getInt("id");
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return id;
}
}

View File

@ -0,0 +1,65 @@
package io.orkes.example.saga.dao;
import io.orkes.example.saga.pojos.Payment;
import java.sql.*;
import java.util.Date;
public class PaymentsDAO extends BaseDAO {
public PaymentsDAO(String url) {
super(url);
}
public String insertPayment(Payment payment) {
Date date = new Date();
Timestamp nowAsTS = new Timestamp(date.getTime());
String sql = "INSERT INTO payments(paymentId, orderId, amount, method, createdAt, status) VALUES(?,?,?,?,?,?);";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, payment.getPaymentId());
pstmt.setString(2, payment.getOrderId());
pstmt.setDouble(3, payment.getAmount());
pstmt.setString(4, payment.getPaymentMethod().toString());
pstmt.setTimestamp(5, nowAsTS);
pstmt.setString(6, payment.getStatus().name());
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
return e.getMessage();
}
return "";
}
public void updatePaymentStatus(Payment payment) {
String sql = "UPDATE payments SET status=? WHERE paymentId=?;";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, payment.getStatus().name());
pstmt.setString(2, payment.getPaymentId());
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public void readPayment(String orderId, Payment payment) {
String sql = "SELECT paymentId, orderId, amount, method, createdAt, status FROM payments WHERE orderId = ?";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, orderId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
payment.setPaymentId(rs.getString("paymentId"));
payment.setOrderId(rs.getString("orderId"));
payment.setAmount(rs.getDouble("amount"));
payment.setCreatedAt(rs.getLong("createdAt"));
payment.setStatus(Payment.Status.valueOf(rs.getString("status")));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}

View File

@ -0,0 +1,75 @@
package io.orkes.example.saga.dao;
import io.orkes.example.saga.pojos.Driver;
import io.orkes.example.saga.pojos.Shipment;
import java.sql.*;
import java.util.Date;
public class ShipmentDAO extends BaseDAO {
public ShipmentDAO(String url) {
super(url);
}
public boolean insertShipment(Shipment shipment) {
Date date = new Date();
Timestamp nowAsTS = new Timestamp(date.getTime());
String sql = "INSERT INTO shipments(orderId,driverId,address,instructions,createdAt,status) VALUES(?,?,?,?,?,?)";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, shipment.getOrderId());
pstmt.setInt(2, shipment.getDriverId());
pstmt.setString(3, shipment.getDeliveryAddress());
pstmt.setString(4, shipment.getDeliveryInstructions());
pstmt.setTimestamp(5, nowAsTS);
pstmt.setString(6, Shipment.Status.SCHEDULED.name());
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
return false;
}
return true;
}
public void cancelShipment(String orderId) {
String sql = "UPDATE shipments SET status=? WHERE orderId=?;";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, Shipment.Status.CANCELED.name());
pstmt.setString(2, orderId);
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public void confirmShipment(String orderId) {
String sql = "UPDATE shipments SET status=? WHERE orderId=?;";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, Shipment.Status.CONFIRMED.name());
pstmt.setString(2, orderId);
pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public void readDriver(int driverId, Driver driver) {
String sql = "SELECT name, contact FROM drivers WHERE id = ?";
try (Connection conn = this.connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, driverId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
driver.setId(driverId);
driver.setName(rs.getString("name"));
driver.setContact(rs.getString("contact"));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}

View File

@ -0,0 +1,8 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class CancelRequest {
private String orderId;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import java.util.ArrayList;
@Data
public class CheckInventoryRequest {
private int restaurantId;
private ArrayList<FoodItem> items;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class Customer {
private int id;
private String email;
private String name;
private String contact;
}

View File

@ -0,0 +1,10 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class Driver {
int id;
String name;
String contact;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class DriverNotificationRequest {
int driverId;
String dropOff;
String pickUp;
String orderId;
}

View File

@ -0,0 +1,19 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import java.util.ArrayList;
@Data
public class FoodDeliveryRequest {
private String customerEmail;
private String customerName;
private String customerContact;
private int restaurantId;
private ArrayList<Object> foodItems;
private ArrayList<String> additionalNotes;
private String address;
private String deliveryInstructions;
private double paymentAmount;
private Object paymentMethod;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class FoodItem {
private String item;
private int quantity;
}

View File

@ -0,0 +1,24 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import java.util.EnumMap;
@Data
public class Order {
public enum Status {
PENDING,
ASSIGNED,
CONFIRMED,
CANCELLED
}
private String orderId;
private Customer customer;
private int restaurantId;
private String deliveryAddress;
private long createdAt;
private Status status;
private OrderDetails orderDetails;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import java.util.ArrayList;
@Data
public class OrderDetails {
private String orderId;
private ArrayList<FoodItem> items;
private ArrayList<String> notes;
}

View File

@ -0,0 +1,18 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import java.util.ArrayList;
@Data
public class OrderRequest {
private String OrderRequestId;
private String customerEmail;
private String customerName;
private String customerContact;
private int restaurantId;
private ArrayList<FoodItem> items;
private ArrayList<String> notes;
private String deliveryAddress;
private String deliveryInstructions;
}

View File

@ -0,0 +1,20 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class Payment {
public enum Status {
PENDING,
FAILED,
SUCCESSFUL,
CANCELED
}
private String paymentId;
private String orderId;
private double amount;
private PaymentMethod paymentMethod;
private Status status;
private long createdAt;
private String errorMsg;
}

View File

@ -0,0 +1,12 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class PaymentDetails {
private String number;
private String expiry;
private int cvv;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class PaymentMethod {
private String type;
private PaymentDetails details;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class PaymentRequest {
private String orderId;
private int customerId;
private float amount;
private PaymentMethod method;
}

View File

@ -0,0 +1,11 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class Restaurant {
int id;
String name;
String address;
String contact;
}

View File

@ -0,0 +1,20 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class Shipment {
public enum Status {
SCHEDULED,
CONFIRMED,
DELIVERED,
CANCELED
}
private int id;
private String orderId;
private int driverId;
private String deliveryAddress;
private String deliveryInstructions;
private long createdAt;
private String status;
}

View File

@ -0,0 +1,10 @@
package io.orkes.example.saga.pojos;
import lombok.Data;
@Data
public class ShippingRequest {
private String orderId;
private String deliveryAddress;
private String deliveryInstructions;
}

View File

@ -0,0 +1,23 @@
package io.orkes.example.saga.service;
import io.orkes.example.saga.dao.InventoryDAO;
import io.orkes.example.saga.pojos.FoodItem;
import io.orkes.example.saga.pojos.Restaurant;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Objects;
@Slf4j
public class InventoryService {
private static final InventoryDAO inventoryDAO = new InventoryDAO("jdbc:sqlite:food_delivery.db");
public static boolean checkAvailability(int restaurantId, ArrayList<FoodItem> items) {
Restaurant restaurant = new Restaurant();
restaurant.setId(restaurantId);
restaurant.setName("");
inventoryDAO.readRestaurant(restaurantId, restaurant);
return !Objects.equals(restaurant.getName(), "");
}
}

View File

@ -0,0 +1,72 @@
package io.orkes.example.saga.service;
import io.orkes.example.saga.dao.OrdersDAO;
import io.orkes.example.saga.pojos.Customer;
import io.orkes.example.saga.pojos.Order;
import io.orkes.example.saga.pojos.OrderDetails;
import io.orkes.example.saga.pojos.OrderRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Slf4j
@AllArgsConstructor
@Service
public class OrderService {
private static final OrdersDAO ORDERS_DAO = new OrdersDAO("jdbc:sqlite:food_delivery.db");
public static String createOrder(OrderRequest orderRequest) {
UUID uuid = UUID.randomUUID();
String uuidAsString = uuid.toString();
Order order = new Order();
order.setOrderId(uuidAsString);
Customer customer = new Customer();
customer.setEmail(orderRequest.getCustomerEmail());
customer.setName(orderRequest.getCustomerName());
customer.setContact(orderRequest.getCustomerContact());
customer.setId(ORDERS_DAO.insertCustomer(customer));
log.info("Upsert customer record in DB with id: {}", customer.getId());
order.setCustomer(customer);
order.setRestaurantId(orderRequest.getRestaurantId());
order.setDeliveryAddress(orderRequest.getDeliveryAddress());
order.setStatus(Order.Status.PENDING);
OrderDetails orderDetails = new OrderDetails();
orderDetails.setOrderId(uuidAsString);
orderDetails.setItems(orderRequest.getItems());
orderDetails.setNotes(orderRequest.getNotes());
order.setOrderDetails(orderDetails);
String error = ORDERS_DAO.insertOrder(order);
if (error.isEmpty()) {
log.info("Created order with id: {}", order.getOrderId());
}
else {
log.error("Order creation failure: {}", error);
return null;
}
return uuidAsString;
}
public static Order getOrder(String orderId) {
Order order = new Order();
ORDERS_DAO.readOrder(orderId, order);
return order;
}
public static void cancelOrder(Order order) {
order.setStatus(Order.Status.CANCELLED);
log.info("Cancelling order {}", order.getOrderId());
ORDERS_DAO.updateOrder(order);
}
}

View File

@ -0,0 +1,85 @@
package io.orkes.example.saga.service;
import io.orkes.example.saga.dao.PaymentsDAO;
import io.orkes.example.saga.pojos.Payment;
import io.orkes.example.saga.pojos.PaymentDetails;
import io.orkes.example.saga.pojos.PaymentMethod;
import io.orkes.example.saga.pojos.PaymentRequest;
import lombok.extern.slf4j.Slf4j;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
@Slf4j
public class PaymentService {
private static final PaymentsDAO paymentsDAO = new PaymentsDAO("jdbc:sqlite:food_delivery.db");
public static Payment createPayment(PaymentRequest paymentRequest) {
UUID uuid = UUID.randomUUID();
String uuidAsString = uuid.toString();
Payment payment = new Payment();
payment.setPaymentId(uuidAsString);
payment.setOrderId(paymentRequest.getOrderId());
payment.setAmount(paymentRequest.getAmount());
payment.setPaymentMethod(paymentRequest.getMethod());
payment.setStatus(Payment.Status.PENDING);
// Check if returned error is non-empty, i.e failure
if (!paymentsDAO.insertPayment(payment).isEmpty()) {
log.error("Failed to process payment for order {}", paymentRequest.getOrderId());
payment.setErrorMsg("Payment creation failure");
payment.setStatus(Payment.Status.FAILED);
}
else {
if(makePayment(payment)) {
payment.setStatus(Payment.Status.SUCCESSFUL);
} else {
payment.setStatus(Payment.Status.FAILED);
}
}
// Record final status
paymentsDAO.updatePaymentStatus(payment);
return payment;
}
public static void cancelPayment(String orderId) {
// Cancel Payment in DB
Payment payment = new Payment();
paymentsDAO.readPayment(orderId, payment);
payment.setStatus(Payment.Status.CANCELED);
paymentsDAO.updatePaymentStatus(payment);
}
private static boolean makePayment(Payment payment) {
if (Objects.equals(payment.getPaymentMethod().getType(), "Credit Card")) {
PaymentDetails details = payment.getPaymentMethod().getDetails();
DateFormat dateFormat= new SimpleDateFormat("MM/yyyy");
Date expiry = new Date();
try {
expiry = dateFormat.parse(details.getExpiry());
} catch (ParseException e) {
payment.setErrorMsg("Invalid expiry date:" + details.getExpiry());
return false;
}
Date today = new Date();
if (today.getTime() > expiry.getTime()) {
payment.setErrorMsg("Expired payment method:" + details.getExpiry());
return false;
}
}
// Ideally an async call would be made with a callback
// But, we're skipping that and assuming payment went through
return true;
}
}

View File

@ -0,0 +1,64 @@
package io.orkes.example.saga.service;
import io.orkes.example.saga.dao.ShipmentDAO;
import io.orkes.example.saga.pojos.Driver;
import io.orkes.example.saga.pojos.Shipment;
import io.orkes.example.saga.pojos.ShippingRequest;
import lombok.extern.slf4j.Slf4j;
import java.util.Random;
@Slf4j
public class ShipmentService {
private static final ShipmentDAO shipmentDAO = new ShipmentDAO("jdbc:sqlite:food_delivery.db");
public static int createShipment(ShippingRequest shippingRequest) {
String orderId = shippingRequest.getOrderId();
Shipment shipment = new Shipment();
shipment.setOrderId(orderId);
shipment.setDeliveryAddress(shippingRequest.getDeliveryAddress());
shipment.setDeliveryInstructions(shippingRequest.getDeliveryInstructions());
int driverId = findDriver();
shipment.setDriverId(driverId);
if (!shipmentDAO.insertShipment(shipment)) {
log.error("Shipment creation for order {} failed.", orderId);
return 0;
}
Driver driver = new Driver();
driver.setName("");
shipmentDAO.readDriver(driverId, driver);
if (driver.getName().isBlank()) {
log.error("Shipment creation for order {} failed as driver in the area is not available.", orderId);
shipmentDAO.cancelShipment(orderId);
return 0;
}
else {
log.info("Assigned driver {} to order with id: {}", driverId, orderId);
shipmentDAO.confirmShipment(orderId);
}
return driverId;
}
public static void cancelDelivery(String orderId) {
shipmentDAO.cancelShipment(orderId);
}
private static int findDriver() {
Random random = new Random();
int driverId = 0;
int counter = 0;
while (counter < 10) {
driverId = random.nextInt(4);
if(driverId !=0) break;
counter += 1;
}
return driverId;
}
}

View File

@ -0,0 +1,61 @@
package io.orkes.example.saga.service;
import com.netflix.conductor.common.metadata.workflow.StartWorkflowRequest;
import io.orkes.conductor.client.WorkflowClient;
import io.orkes.example.saga.pojos.FoodDeliveryRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@AllArgsConstructor
@Service
public class WorkflowService {
private final WorkflowClient workflowClient;
private final Environment environment;
public Map<String, Object> startFoodDeliveryWorkflow(FoodDeliveryRequest foodDeliveryRequest) {
StartWorkflowRequest request = new StartWorkflowRequest();
request.setName("FoodDeliveryWorkflow");
request.setVersion(1);
request.setCorrelationId("api-triggered");
String TASK_DOMAIN_PROPERTY = "conductor.worker.all.domain";
String domain = environment.getProperty(TASK_DOMAIN_PROPERTY, String.class, "");
if (!domain.isEmpty()) {
Map<String, String> taskToDomain = new HashMap<>();
taskToDomain.put("*", domain);
request.setTaskToDomain(taskToDomain);
}
Map<String, Object> inputData = new HashMap<>();
inputData.put("customerEmail", foodDeliveryRequest.getCustomerEmail());
inputData.put("customerName", foodDeliveryRequest.getCustomerName());
inputData.put("customerContact", foodDeliveryRequest.getCustomerContact());
inputData.put("restaurantId", foodDeliveryRequest.getRestaurantId());
inputData.put("foodItems", foodDeliveryRequest.getFoodItems());
inputData.put("additionalNotes", foodDeliveryRequest.getAdditionalNotes());
inputData.put("address", foodDeliveryRequest.getAddress());
inputData.put("deliveryInstructions", foodDeliveryRequest.getDeliveryInstructions());
inputData.put("paymentAmount", foodDeliveryRequest.getPaymentAmount());
inputData.put("paymentMethod", foodDeliveryRequest.getPaymentMethod());
request.setInput(inputData);
String workflowId = "";
try {
workflowId = workflowClient.startWorkflow(request);
log.info("Workflow id: {}", workflowId);
} catch (Exception ex) {
ex.printStackTrace(System.out);
return Map.of("error", "Order creation failure", "detail", ex.toString());
}
return Map.of("workflowId", workflowId);
}
}

View File

@ -0,0 +1,130 @@
package io.orkes.example.saga.workers;
import com.netflix.conductor.common.metadata.tasks.TaskResult;
import com.netflix.conductor.sdk.workflow.task.WorkerTask;
import io.orkes.example.saga.pojos.*;
import io.orkes.example.saga.service.InventoryService;
import io.orkes.example.saga.service.OrderService;
import io.orkes.example.saga.service.PaymentService;
import io.orkes.example.saga.service.ShipmentService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@AllArgsConstructor
@Component
@ComponentScan(basePackages = {"io.orkes"})
public class ConductorWorkers {
/**
* Note: Using this setting, up to 5 tasks will run in parallel, with tasks being polled every 200ms
*/
@WorkerTask(value = "order_food", threadCount = 3, pollingInterval = 300)
public TaskResult orderFoodTask(OrderRequest orderRequest) {
String orderId = OrderService.createOrder(orderRequest);
TaskResult result = new TaskResult();
Map<String, Object> output = new HashMap<>();
if(orderId != null) {
output.put("orderId", orderId);
result.setOutputData(output);
result.setStatus(TaskResult.Status.COMPLETED);
} else {
output.put("orderId", null);
result.setStatus(TaskResult.Status.FAILED);
}
return result;
}
@WorkerTask(value = "check_inventory", threadCount = 2, pollingInterval = 300)
public TaskResult checkInventoryTask(CheckInventoryRequest checkInventoryRequest) {
int restaurantId = checkInventoryRequest.getRestaurantId();
ArrayList<FoodItem> items = checkInventoryRequest.getItems();
boolean availability = InventoryService.checkAvailability(restaurantId, items);
TaskResult result = new TaskResult();
if (availability) {
result.setStatus(TaskResult.Status.COMPLETED);
} else {
result.setReasonForIncompletion("Restaurant is closed");
result.setStatus(TaskResult.Status.FAILED_WITH_TERMINAL_ERROR);
}
return result;
}
@WorkerTask(value = "make_payment", threadCount = 2, pollingInterval = 300)
public TaskResult makePaymentTask(PaymentRequest paymentRequest) {
TaskResult result = new TaskResult();
Payment payment = PaymentService.createPayment(paymentRequest);
Map<String, Object> output = new HashMap<>();
output.put("orderId", payment.getOrderId());
output.put("paymentId", payment.getPaymentId());
output.put("paymentStatus", payment.getStatus().name());
if(payment.getStatus() == Payment.Status.SUCCESSFUL) {
result.setStatus(TaskResult.Status.COMPLETED);
} else {
output.put("error", payment.getErrorMsg());
result.setStatus(TaskResult.Status.FAILED_WITH_TERMINAL_ERROR);
}
result.setOutputData(output);
return result;
}
@WorkerTask(value = "ship_food", threadCount = 2, pollingInterval = 300)
public TaskResult shipFoodTask(ShippingRequest shippingRequest) {
TaskResult result = new TaskResult();
Map<String, Object> output = new HashMap<>();
int driverId = ShipmentService.createShipment(shippingRequest);
if (driverId != 0) {
result.setStatus(TaskResult.Status.COMPLETED);
} else {
result.setStatus(TaskResult.Status.FAILED);
}
return result;
}
@WorkerTask(value = "notify_driver", threadCount = 2, pollingInterval = 300)
public Map<String, Object> checkForDriverNotifications(DriverNotificationRequest driverNotificationRequest) {
Map<String, Object> result = new HashMap<>();
return result;
}
@WorkerTask(value = "notify_customer", threadCount = 2, pollingInterval = 300)
public Map<String, Object> checkForCustomerNotifications(Order order) {
Map<String, Object> result = new HashMap<>();
return result;
}
//
@WorkerTask(value = "cancel_payment", threadCount = 2, pollingInterval = 300)
public Map<String, Object> cancelPaymentTask(CancelRequest cancelRequest) {
Map<String, Object> result = new HashMap<>();
PaymentService.cancelPayment(cancelRequest.getOrderId());
return result;
}
@WorkerTask(value = "cancel_delivery", threadCount = 2, pollingInterval = 300)
public Map<String, Object> cancelDeliveryTask(CancelRequest cancelRequest) {
Map<String, Object> result = new HashMap<>();
ShipmentService.cancelDelivery(cancelRequest.getOrderId());
return result;
}
@WorkerTask(value = "cancel_order", threadCount = 2, pollingInterval = 300)
public Map<String, Object> cancelOrderTask(CancelRequest cancelRequest) {
Map<String, Object> result = new HashMap<>();
Order order = OrderService.getOrder(cancelRequest.getOrderId());
OrderService.cancelOrder(order);
return result;
}
}

View File

@ -0,0 +1,32 @@
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
springdoc.swagger-ui.path=/swagger-ui.html
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=false
# Local app server port
server.port=8081
# Playground
# Obtain key and secret by logging into https://play.orkes.io/
# and navigating to applications menu, create an application and generate key/secret
conductor.server.url=https://play.orkes.io/api
conductor.security.client.key-id=<key>
conductor.security.client.secret=<secret>
# Task Domain
conductor.worker.all.domain=saga
conductor.worker.all.pollingInterval=22
# DB Setup
spring.jpa.database-platform=com.springboot.sqlite.SQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:sqlite:food_delivery.db
spring.datasource.driver-class-name = org.sqlite.JDBC
spring.datasource.username=admin
spring.datasource.password=admin

View File

@ -35,7 +35,7 @@
</dependencies>
<properties>
<spring.version>6.1.2</spring.version>
<spring.version>6.1.5</spring.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
<spring-boot.version>3.2.1</spring-boot.version>
</properties>

Some files were not shown because too many files have changed in this diff Show More