From 6d2314a218d9023f75875aab8008e747a71b6f07 Mon Sep 17 00:00:00 2001 From: pandianDK Date: Thu, 19 Oct 2023 11:33:02 +0530 Subject: [PATCH 1/2] #2681 : add messaging design pattern implementation with kafka --- .../.mvn/wrapper/maven-wrapper.properties | 2 + messaging/README.md | 6 + messaging/img.png | Bin 0 -> 75951 bytes messaging/mvnw | 308 ++++++++++++++++++ messaging/mvnw.cmd | 205 ++++++++++++ messaging/pom.xml | 81 +++++ .../messaging/MessagingApplication.java | 13 + .../messaging/controller/OrderController.java | 42 +++ .../exception/ConsumerNotFoundException.java | 8 + .../exception/OrderWithZeroItemException.java | 8 + .../RestaurantNotFoundException.java | 9 + .../messaging/kafka/KafkaConsumer.java | 38 +++ .../messaging/kafka/KafkaProducer.java | 24 ++ .../model/MenuItemIdAndQuantity.java | 35 ++ .../com/iluwatar/messaging/model/Order.java | 91 ++++++ .../messaging/model/OrderRequest.java | 36 ++ .../messaging/service/OrderService.java | 92 ++++++ .../src/main/resources/application.properties | 6 + .../messaging/MessagingApplicationTests.java | 13 + .../OrderControllerIntegrationTest.java | 117 +++++++ .../service/OrderServiceIntegrationTest.java | 64 ++++ 21 files changed, 1198 insertions(+) create mode 100644 messaging/.mvn/wrapper/maven-wrapper.properties create mode 100644 messaging/README.md create mode 100644 messaging/img.png create mode 100755 messaging/mvnw create mode 100644 messaging/mvnw.cmd create mode 100644 messaging/pom.xml create mode 100644 messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/model/Order.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java create mode 100644 messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java create mode 100644 messaging/src/main/resources/application.properties create mode 100644 messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java create mode 100644 messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java create mode 100644 messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java diff --git a/messaging/.mvn/wrapper/maven-wrapper.properties b/messaging/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000000..5f0536eb7434 --- /dev/null +++ b/messaging/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/messaging/README.md b/messaging/README.md new file mode 100644 index 000000000000..152ea6b2d579 --- /dev/null +++ b/messaging/README.md @@ -0,0 +1,6 @@ +## MESSAGING DESIGN PATTERN + +Event Driven / Message Stream Based MicroService + + +![img.png](img.png) diff --git a/messaging/img.png b/messaging/img.png new file mode 100644 index 0000000000000000000000000000000000000000..46d6273aeab2084ef78ad6413322dda088dd7666 GIT binary patch literal 75951 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 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/messaging/mvnw.cmd b/messaging/mvnw.cmd new file mode 100644 index 000000000000..95ba6f54ac52 --- /dev/null +++ b/messaging/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/messaging/pom.xml b/messaging/pom.xml new file mode 100644 index 000000000000..e85b40b28610 --- /dev/null +++ b/messaging/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.4 + + + com.iluwatar + messaging + 0.0.1-SNAPSHOT + messaging + messaging + + 11 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.apache.commons + commons-collections4 + 4.4 + + + + org.springframework.kafka + spring-kafka + 3.0.11 + + + + org.springframework.kafka + spring-kafka-test + 3.0.11 + test + + + + org.testcontainers + kafka + 1.19.1 + test + + + + com.fasterxml.jackson.core + jackson-databind + 2.15.3 + + + + org.springframework.boot + spring-boot-starter-web + 3.1.4 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + s + diff --git a/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java b/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java new file mode 100644 index 000000000000..9c04eca1717a --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java @@ -0,0 +1,13 @@ +package com.iluwatar.messaging; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MessagingApplication { + + public static void main(String[] args) { + SpringApplication.run(MessagingApplication.class, args); + } + +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java b/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java new file mode 100644 index 000000000000..4a802dd61189 --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java @@ -0,0 +1,42 @@ +package com.iluwatar.messaging.controller; + +import com.iluwatar.messaging.exception.ConsumerNotFoundException; +import com.iluwatar.messaging.exception.OrderWithZeroItemException; +import com.iluwatar.messaging.exception.RestaurantNotFoundException; +import com.iluwatar.messaging.model.Order; +import com.iluwatar.messaging.model.OrderRequest; +import com.iluwatar.messaging.service.OrderService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.NonNull; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/order") +public class OrderController { + + private final OrderService orderService; + + public OrderController(OrderService orderService) { + this.orderService = orderService; + } + + @PostMapping("/place") public ResponseEntity postOrder(@RequestBody @NonNull OrderRequest orderRequest) { + + if (orderRequest.getConsumerId() == 0 || orderRequest.getRestaurantId() == 0) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + try { + return new ResponseEntity<>(orderService.createOrder(orderRequest.getConsumerId(), orderRequest.getRestaurantId(), orderRequest.getMenuItemIdAndQuantityList()), + HttpStatus.CREATED); + } catch (ConsumerNotFoundException | RestaurantNotFoundException | OrderWithZeroItemException e) { + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + + } + +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java b/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java new file mode 100644 index 000000000000..a580c1f6931f --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java @@ -0,0 +1,8 @@ +package com.iluwatar.messaging.exception; + +public class ConsumerNotFoundException extends Exception{ + + public ConsumerNotFoundException(long consumerId) { + super(consumerId + "Is Not found"); + } +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java b/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java new file mode 100644 index 000000000000..5a4835ec851c --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java @@ -0,0 +1,8 @@ +package com.iluwatar.messaging.exception; + +public class OrderWithZeroItemException extends Exception { + + public OrderWithZeroItemException() { + super("No Item Present in order"); + } +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java b/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java new file mode 100644 index 000000000000..9929b74177c2 --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java @@ -0,0 +1,9 @@ +package com.iluwatar.messaging.exception; + +public class RestaurantNotFoundException extends Exception{ + + public RestaurantNotFoundException(long restaurantId) { + super(restaurantId + "Is Not found"); + } +} + diff --git a/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java new file mode 100644 index 000000000000..a7b33cebb15b --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java @@ -0,0 +1,38 @@ +package com.iluwatar.messaging.kafka; + +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CountDownLatch; + +@Component +public class KafkaConsumer { + + private static final Logger LOGGER = LoggerFactory.getLogger(KafkaConsumer.class); + + private CountDownLatch latch = new CountDownLatch(1); + private String payload; + + public void resetLatch() { + latch = new CountDownLatch(1); + } + + @KafkaListener(topics = "${app.message.topic.default}") + public void receive(ConsumerRecord consumerRecord) { + LOGGER.info("received payload='{}'", consumerRecord.toString()); + payload = consumerRecord.toString(); + latch.countDown(); + } + + public CountDownLatch getLatch() { + return latch; + } + + public String getPayload() { + return payload; + } + +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java new file mode 100644 index 000000000000..994b1bca0090 --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java @@ -0,0 +1,24 @@ +package com.iluwatar.messaging.kafka; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +public class KafkaProducer { + + private static final Logger LOGGER = LoggerFactory.getLogger(KafkaProducer.class); + + + private final KafkaTemplate kafkaTemplate; + + public KafkaProducer(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + public void send(String topic, String payload) { + LOGGER.info("sending payload='{}' to topic='{}'", payload, topic); + kafkaTemplate.send(topic, payload); + } +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java b/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java new file mode 100644 index 000000000000..56a1b71b1709 --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java @@ -0,0 +1,35 @@ +package com.iluwatar.messaging.model; + +public class MenuItemIdAndQuantity { + + private String item; + + private int quantity; + + public MenuItemIdAndQuantity() { + quantity = 1; + } + + public MenuItemIdAndQuantity(String item, int quantity) { + this.item = item; + this.quantity = quantity; + } + + public String getItem() { + return item; + } + + public void setItem(String item) { + this.item = item; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } +} + + diff --git a/messaging/src/main/java/com/iluwatar/messaging/model/Order.java b/messaging/src/main/java/com/iluwatar/messaging/model/Order.java new file mode 100644 index 000000000000..b0501bbb52b1 --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/model/Order.java @@ -0,0 +1,91 @@ +package com.iluwatar.messaging.model; + +import java.util.List; + +public class Order { + + private long orderId; + + private long consumerId; + + private long restaurantId; + + private List menuItemIdAndQuantityList; + + public long getOrderId() { + return orderId; + } + + public void setOrderId(long orderId) { + this.orderId = orderId; + } + + public long getRestaurantId() { + return restaurantId; + } + + public void setRestaurantId(long restaurantId) { + this.restaurantId = restaurantId; + } + + public List getMenuItemIdAndQuantityList() { + return menuItemIdAndQuantityList; + } + + public void setMenuItemIdAndQuantityList(List menuItemIdAndQuantityList) { + this.menuItemIdAndQuantityList = menuItemIdAndQuantityList; + } + + public long getConsumerId() { + return consumerId; + } + + public void setConsumerId(long consumerId) { + this.consumerId = consumerId; + } + + public static OrderBuilder builder() { + return new OrderBuilder(); + } + public static final class OrderBuilder { + private long orderId; + private long consumerId; + private long restaurantId; + private List menuItemIdAndQuantityList; + + private OrderBuilder() { + } + + + public OrderBuilder orderId(long orderId) { + this.orderId = orderId; + return this; + } + + public OrderBuilder consumerId(long consumerId) { + this.consumerId = consumerId; + return this; + } + + public OrderBuilder restaurantId(long restaurantId) { + this.restaurantId = restaurantId; + return this; + } + + public OrderBuilder menuItemIdAndQuantityList(List menuItemIdAndQuantityList) { + this.menuItemIdAndQuantityList = menuItemIdAndQuantityList; + return this; + } + + public Order build() { + Order order = new Order(); + order.setOrderId(orderId); + order.setConsumerId(consumerId); + order.setRestaurantId(restaurantId); + order.setMenuItemIdAndQuantityList(menuItemIdAndQuantityList); + return order; + } + } +} + + diff --git a/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java b/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java new file mode 100644 index 000000000000..8747ebddf54c --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java @@ -0,0 +1,36 @@ +package com.iluwatar.messaging.model; + +import java.util.List; + +public class OrderRequest { + + private long consumerId; + + private long restaurantId; + + private List menuItemIdAndQuantityList; + + public long getConsumerId() { + return consumerId; + } + + public void setConsumerId(long consumerId) { + this.consumerId = consumerId; + } + + public long getRestaurantId() { + return restaurantId; + } + + public void setRestaurantId(long restaurantId) { + this.restaurantId = restaurantId; + } + + public List getMenuItemIdAndQuantityList() { + return menuItemIdAndQuantityList; + } + + public void setMenuItemIdAndQuantityList(List menuItemIdAndQuantityList) { + this.menuItemIdAndQuantityList = menuItemIdAndQuantityList; + } +} diff --git a/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java b/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java new file mode 100644 index 000000000000..10fd2583dd23 --- /dev/null +++ b/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java @@ -0,0 +1,92 @@ +package com.iluwatar.messaging.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iluwatar.messaging.exception.ConsumerNotFoundException; +import com.iluwatar.messaging.exception.OrderWithZeroItemException; +import com.iluwatar.messaging.exception.RestaurantNotFoundException; +import com.iluwatar.messaging.kafka.KafkaProducer; +import com.iluwatar.messaging.model.MenuItemIdAndQuantity; +import com.iluwatar.messaging.model.Order; +import jakarta.annotation.PostConstruct; +import org.apache.commons.collections4.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Service +public class OrderService { + + private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class); + + private final Map orderMap = new HashMap<>(); + + private final Set consumers = new HashSet<>(); + private final Set restaurants = new HashSet<>(); + + private final KafkaProducer kafkaProducer; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Value("${app.message.topic.default}") + private String defaultTopic; + + public OrderService(KafkaProducer kafkaProducer) { + this.kafkaProducer = kafkaProducer; + } + + @PostConstruct + void init(){ + consumers.add(1001L); + restaurants.add(2001L); + } + + public Order createOrder(long consumerId, long restaurantId, List lineItems) + throws ConsumerNotFoundException, RestaurantNotFoundException, OrderWithZeroItemException { + + if (!consumers.contains(consumerId)) { + throw new ConsumerNotFoundException(consumerId); + } + + if (!restaurants.contains(restaurantId)) { + throw new RestaurantNotFoundException(restaurantId); + } + + if (CollectionUtils.isEmpty(lineItems)) { + throw new OrderWithZeroItemException(); + } + + Order receivedOrder = Order.builder().orderId(newOrderId()) + .menuItemIdAndQuantityList(lineItems) + .restaurantId(restaurantId) + .consumerId(consumerId) + .build(); + + try { + placeOrder(receivedOrder); + } catch (JsonProcessingException e) { + LOGGER.error("order failed to send due to exception", e); + } + + return receivedOrder; + } + + private void placeOrder(Order receivedOrder) throws JsonProcessingException { + this.orderMap.put(receivedOrder.getOrderId(), receivedOrder); + String orderPayload = objectMapper.writeValueAsString(receivedOrder); + this.kafkaProducer.send(defaultTopic, orderPayload); + + } + + private int newOrderId() { + return orderMap.keySet().size() + 1; + } + +} diff --git a/messaging/src/main/resources/application.properties b/messaging/src/main/resources/application.properties new file mode 100644 index 000000000000..74b2cdfe3b7b --- /dev/null +++ b/messaging/src/main/resources/application.properties @@ -0,0 +1,6 @@ + +spring.kafka.consumer.auto-offset-reset=earliest +spring.kafka.consumer.group-id=messaging +spring.kafka.bootstrap-servers=localhost:9092 +app.message.topic.default=order-topic + diff --git a/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java b/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java new file mode 100644 index 000000000000..4fe5b3f1ea40 --- /dev/null +++ b/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java @@ -0,0 +1,13 @@ +package com.iluwatar.messaging; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class MessagingApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java b/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java new file mode 100644 index 000000000000..04102e5f5d16 --- /dev/null +++ b/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java @@ -0,0 +1,117 @@ +package com.iluwatar.messaging.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iluwatar.messaging.model.MenuItemIdAndQuantity; +import com.iluwatar.messaging.model.OrderRequest; +import jakarta.servlet.ServletContext; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.RequestBuilder; +import org.springframework.test.web.servlet.ResultActions; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(SpringExtension.class) +@SpringBootTest +@AutoConfigureMockMvc +@DirtiesContext +@EmbeddedKafka(partitions = 1, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"}) +public class OrderControllerIntegrationTest { + + ObjectMapper objectMapper = new ObjectMapper(); + @Autowired + private MockMvc mockMvc; + + @Test + void shouldPlaceTheOrderAndReturn_200WhenOrderIsOk() throws Exception { + + OrderRequest orderRequest = new OrderRequest(); + orderRequest.setConsumerId(1001L); + orderRequest.setRestaurantId(2001L); + orderRequest.setMenuItemIdAndQuantityList(testMenuItems()); + + RequestBuilder requestBuilder = new RequestBuilder() { + @Override public MockHttpServletRequest buildRequest(ServletContext servletContext) { + MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest(); + mockHttpServletRequest.setRequestURI("/order/place"); + mockHttpServletRequest.setMethod("POST"); + try { + mockHttpServletRequest.setContent(objectMapper.writeValueAsString(orderRequest).getBytes(StandardCharsets.UTF_8)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + mockHttpServletRequest.setContentType(APPLICATION_JSON_VALUE); + return mockHttpServletRequest; + } + }; + + ResultActions resultActions = this.mockMvc.perform(requestBuilder).andExpect(status().isCreated()); + } + + @Test + void shouldPlaceTheOrderAndReturn_400WhenOrderIsInvalid() throws Exception { + OrderRequest orderRequest = new OrderRequest(); + orderRequest.setConsumerId(1001L); + orderRequest.setMenuItemIdAndQuantityList(testMenuItems()); + + RequestBuilder requestBuilder = new RequestBuilder() { + @Override public MockHttpServletRequest buildRequest(ServletContext servletContext) { + MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest(); + mockHttpServletRequest.setRequestURI("/order/place"); + mockHttpServletRequest.setMethod("POST"); + try { + mockHttpServletRequest.setContent(objectMapper.writeValueAsString(orderRequest).getBytes(StandardCharsets.UTF_8)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + mockHttpServletRequest.setContentType(APPLICATION_JSON_VALUE); + return mockHttpServletRequest; + } + }; + + ResultActions resultActions = this.mockMvc.perform(requestBuilder).andExpect(status().isBadRequest()); + } + + @Test + void shouldPlaceTheOrderAndReturn_500WhenOrderDoesNotHaveItems() throws Exception { + OrderRequest orderRequest = new OrderRequest(); + orderRequest.setConsumerId(1001L); + orderRequest.setRestaurantId(2001L); + orderRequest.setMenuItemIdAndQuantityList(null); + + RequestBuilder requestBuilder = new RequestBuilder() { + @Override public MockHttpServletRequest buildRequest(ServletContext servletContext) { + MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest(); + mockHttpServletRequest.setRequestURI("/order/place"); + mockHttpServletRequest.setMethod("POST"); + try { + mockHttpServletRequest.setContent(objectMapper.writeValueAsString(orderRequest).getBytes(StandardCharsets.UTF_8)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + mockHttpServletRequest.setContentType(APPLICATION_JSON_VALUE); + return mockHttpServletRequest; + } + }; + + ResultActions resultActions = this.mockMvc.perform(requestBuilder).andExpect(status().isInternalServerError()); + } + + @NotNull private List testMenuItems() { + return List.of(new MenuItemIdAndQuantity("CAKE", 1)); + } +} diff --git a/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java b/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java new file mode 100644 index 000000000000..eeed502fe6c0 --- /dev/null +++ b/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java @@ -0,0 +1,64 @@ +package com.iluwatar.messaging.service; + +import com.iluwatar.messaging.exception.ConsumerNotFoundException; +import com.iluwatar.messaging.exception.OrderWithZeroItemException; +import com.iluwatar.messaging.exception.RestaurantNotFoundException; +import com.iluwatar.messaging.kafka.KafkaConsumer; +import com.iluwatar.messaging.model.MenuItemIdAndQuantity; +import com.iluwatar.messaging.model.Order; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.test.annotation.DirtiesContext; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest +@DirtiesContext +@EmbeddedKafka(partitions = 1, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"}) +public class OrderServiceIntegrationTest { + + @Autowired OrderService orderService; + + @Autowired KafkaConsumer kafkaConsumer; + + @Test + void shouldPlaceTheOrderAndSendOrderEvent() throws OrderWithZeroItemException, ConsumerNotFoundException, RestaurantNotFoundException, InterruptedException { + + Order order = orderService.createOrder(1001L, 2001L, testMenuItems()); + boolean messageConsumed = kafkaConsumer.getLatch().await(10, TimeUnit.SECONDS); + + assertNotNull(order); + assertTrue(order.getOrderId() > 0); + assertThat(kafkaConsumer.getPayload().contains("1001")); + + } + + @Test + void shouldThrowConsumerNotFoundException() { + Assertions.assertThrows(ConsumerNotFoundException.class, ()->orderService.createOrder(1, 2001, testMenuItems())); + } + + @Test + void shouldThrowRestaurantNotFoundException() { + Assertions.assertThrows(RestaurantNotFoundException.class, ()->orderService.createOrder(1001L, 1, testMenuItems())); + } + + @Test + void shouldThrowOrderWithZeroItemException() { + Assertions.assertThrows(OrderWithZeroItemException.class, ()->orderService.createOrder(1001L, 2001, null)); + } + + @NotNull private List testMenuItems() { + return List.of(new MenuItemIdAndQuantity("CAKE", 1)); + } + +} From ea23d31c83f8d9891e9fb16aaad184812dcc368b Mon Sep 17 00:00:00 2001 From: pandianDK Date: Tue, 31 Oct 2023 10:21:38 +0530 Subject: [PATCH 2/2] #2681 : add refactoring on PR#2712 -- refactoring source, test -- clean up in pom file -- updated comments in source -- refactoring the readme wiki --- .../physiccomponent/PhysicComponent.java | 24 ++++++ .../.mvn/wrapper/maven-wrapper.properties | 2 - messaging/README.md | 57 ++++++++++++- .../{img.png => etc/high-level-design.png} | Bin messaging/etc/messaging-urm.png | Bin 0 -> 54641 bytes messaging/pom.xml | 80 +++++++++++++----- .../messaging/MessagingApplication.java | 32 +++++++ .../messaging/controller/OrderController.java | 24 ++++++ .../exception/ConsumerNotFoundException.java | 24 ++++++ .../exception/OrderWithZeroItemException.java | 24 ++++++ .../RestaurantNotFoundException.java | 24 ++++++ .../messaging/kafka/KafkaConsumer.java | 24 ++++++ .../messaging/kafka/KafkaProducer.java | 24 ++++++ .../model/MenuItemIdAndQuantity.java | 44 ++++++---- .../com/iluwatar/messaging/model/Order.java | 24 ++++++ .../messaging/model/OrderRequest.java | 34 ++++++++ .../messaging/service/OrderService.java | 26 +++++- .../src/main/resources/application.properties | 25 ++++++ .../messaging/MessagingApplicationTests.java | 36 ++++++++ .../OrderControllerIntegrationTest.java | 53 +++++++++--- .../service/OrderServiceIntegrationTest.java | 28 +++++- 21 files changed, 554 insertions(+), 55 deletions(-) delete mode 100644 messaging/.mvn/wrapper/maven-wrapper.properties rename messaging/{img.png => etc/high-level-design.png} (100%) create mode 100644 messaging/etc/messaging-urm.png diff --git a/component/src/main/java/com/iluwatar/component/component/physiccomponent/PhysicComponent.java b/component/src/main/java/com/iluwatar/component/component/physiccomponent/PhysicComponent.java index d7f55153f401..25e2dfd40b8b 100644 --- a/component/src/main/java/com/iluwatar/component/component/physiccomponent/PhysicComponent.java +++ b/component/src/main/java/com/iluwatar/component/component/physiccomponent/PhysicComponent.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.component.component.physiccomponent; import com.iluwatar.component.GameObject; diff --git a/messaging/.mvn/wrapper/maven-wrapper.properties b/messaging/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 5f0536eb7434..000000000000 --- a/messaging/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,2 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/messaging/README.md b/messaging/README.md index 152ea6b2d579..edf25c593aeb 100644 --- a/messaging/README.md +++ b/messaging/README.md @@ -1,6 +1,61 @@ ## MESSAGING DESIGN PATTERN + +### Also Known As : Event Driven / Message Stream Based MicroService +### Intent: +Sample implementation for Kafka Bases messaging service +and events will be published based on transactions + +### Explanation + +Use asynchronous messaging for inter-service communication. Services communicating by exchanging messages over messaging channels. + +There are several different styles of asynchronous communication: + +Request/response - a service sends a request message to a recipient and expects to receive a reply message promptly +Notifications - a sender sends a message a recipient but does not expect a reply. Nor is one sent. +Request/asynchronous response - a service sends a request message to a recipient and expects to receive a reply message eventually +Publish/subscribe - a service publishes a message to zero or more recipients +Publish/asynchronous response - a service publishes a request to one or recipients, some of whom send back a reply + +#### This pattern has the following benefits: + +Loose runtime coupling since it decouples the message sender from the consumer +* Improved availability since the message broker buffers messages until the consumer is able to process them +* Supports a variety of communication patterns including request/reply, notifications, request/async response, publish/subscribe, publish/async response etc +* This pattern has the following drawbacks: + +### Class diagram: +![img.png](etc/messaging-urm.png) + +#### High Level Design: +![img.png](etc/high-level-design.png) + + +### Applicability: +* Its more appropriate where the system expecting Pub/Sub based communication +* If immediate notification is required between two microservices, then this pattern will help on the same + +### Tutorials : +1. https://medium.com/design-microservices-architecture-with-patterns/microservices-asynchronous-message-based-communication-6643bee06123 +2. https://microservices.io/patterns/communication-style/messaging.html + +### Known uses: +* Event Driven MicroService - Communication between more than one microservice using messaging channel +* Distributed Transaction Service - Auditing and Notifying system from one to another + +### Consequences: +Additional complexity of message broker, which must be highly available +This pattern has the following issues: + +- Request/reply-style communication is more complex + +### Related patterns : +* The Saga pattern and CQRS pattern use messaging : https://microservices.io/patterns/data/saga.html , https://microservices.io/patterns/data/cqrs.html +* The Transactional Outbox pattern enables messages to be sent as part of a database transaction : https://microservices.io/patterns/data/transactional-outbox.html -![img.png](img.png) +### Credits: +``` Chris Richardson ``` +Experienced software architect, author of POJOs in Action, the creator of the original CloudFoundry.com diff --git a/messaging/img.png b/messaging/etc/high-level-design.png similarity index 100% rename from messaging/img.png rename to messaging/etc/high-level-design.png diff --git a/messaging/etc/messaging-urm.png b/messaging/etc/messaging-urm.png new file mode 100644 index 0000000000000000000000000000000000000000..088653318c2ca72ea90620b39ed4daa85aa16997 GIT binary patch literal 54641 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 z + 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.1.4 - + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + com.iluwatar messaging 0.0.1-SNAPSHOT messaging messaging - - 11 - org.springframework.boot @@ -37,33 +60,27 @@ org.springframework.kafka spring-kafka - 3.0.11 org.springframework.kafka spring-kafka-test - 3.0.11 - test - - - - org.testcontainers - kafka - 1.19.1 test com.fasterxml.jackson.core jackson-databind - 2.15.3 org.springframework.boot spring-boot-starter-web - 3.1.4 + + + + org.projectlombok + lombok @@ -75,7 +92,32 @@ org.springframework.boot spring-boot-maven-plugin + + + + com.iluwatar.urm + urm-maven-plugin + 2.1.1 + + + ${project.basedir}/etc + + com.iluwatar.messaging + + true + false + graphviz + + + + process-classes + + map + + + + - s + diff --git a/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java b/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java index 9c04eca1717a..84dfc1d3a449 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java +++ b/messaging/src/main/java/com/iluwatar/messaging/MessagingApplication.java @@ -1,8 +1,40 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; + +/*** + * Design pattern : Event Driven / Message Stream Based MicroService + * An Implementation for Kafka Based messaging service and events will be published based on transactions, and + * it has implementation of asynchronous messaging for inter-service communication. Services communicating by + * exchanging messages over messaging channels. + */ + @SpringBootApplication public class MessagingApplication { diff --git a/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java b/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java index 4a802dd61189..9e1bfcbd4ab1 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java +++ b/messaging/src/main/java/com/iluwatar/messaging/controller/OrderController.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.controller; import com.iluwatar.messaging.exception.ConsumerNotFoundException; diff --git a/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java b/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java index a580c1f6931f..8b0337c279d2 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java +++ b/messaging/src/main/java/com/iluwatar/messaging/exception/ConsumerNotFoundException.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.exception; public class ConsumerNotFoundException extends Exception{ diff --git a/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java b/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java index 5a4835ec851c..8583eab4dd21 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java +++ b/messaging/src/main/java/com/iluwatar/messaging/exception/OrderWithZeroItemException.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.exception; public class OrderWithZeroItemException extends Exception { diff --git a/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java b/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java index 9929b74177c2..b8f0e2eefb00 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java +++ b/messaging/src/main/java/com/iluwatar/messaging/exception/RestaurantNotFoundException.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.exception; public class RestaurantNotFoundException extends Exception{ diff --git a/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java index a7b33cebb15b..1c99d9b303ef 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java +++ b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaConsumer.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.kafka; import org.apache.kafka.clients.consumer.ConsumerRecord; diff --git a/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java index 994b1bca0090..8bada33a80c7 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java +++ b/messaging/src/main/java/com/iluwatar/messaging/kafka/KafkaProducer.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.kafka; import org.slf4j.Logger; diff --git a/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java b/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java index 56a1b71b1709..186ced6e5636 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java +++ b/messaging/src/main/java/com/iluwatar/messaging/model/MenuItemIdAndQuantity.java @@ -1,5 +1,34 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.model; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter public class MenuItemIdAndQuantity { private String item; @@ -15,21 +44,6 @@ public MenuItemIdAndQuantity(String item, int quantity) { this.quantity = quantity; } - public String getItem() { - return item; - } - - public void setItem(String item) { - this.item = item; - } - - public int getQuantity() { - return quantity; - } - - public void setQuantity(int quantity) { - this.quantity = quantity; - } } diff --git a/messaging/src/main/java/com/iluwatar/messaging/model/Order.java b/messaging/src/main/java/com/iluwatar/messaging/model/Order.java index b0501bbb52b1..9faa3e29f01f 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/model/Order.java +++ b/messaging/src/main/java/com/iluwatar/messaging/model/Order.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.model; import java.util.List; diff --git a/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java b/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java index 8747ebddf54c..1256dac639b1 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java +++ b/messaging/src/main/java/com/iluwatar/messaging/model/OrderRequest.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.model; import java.util.List; @@ -10,6 +34,16 @@ public class OrderRequest { private List menuItemIdAndQuantityList; + public OrderRequest() { + super(); + } + + public OrderRequest(long consumerId, long restaurantId, List menuItemIdAndQuantityList) { + this.consumerId = consumerId; + this.restaurantId = restaurantId; + this.menuItemIdAndQuantityList = menuItemIdAndQuantityList; + } + public long getConsumerId() { return consumerId; } diff --git a/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java b/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java index 10fd2583dd23..d442bc426d2b 100644 --- a/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java +++ b/messaging/src/main/java/com/iluwatar/messaging/service/OrderService.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.service; import com.fasterxml.jackson.core.JsonProcessingException; @@ -8,13 +32,13 @@ import com.iluwatar.messaging.kafka.KafkaProducer; import com.iluwatar.messaging.model.MenuItemIdAndQuantity; import com.iluwatar.messaging.model.Order; -import jakarta.annotation.PostConstruct; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import javax.annotation.PostConstruct; import java.util.HashMap; import java.util.HashSet; import java.util.List; diff --git a/messaging/src/main/resources/application.properties b/messaging/src/main/resources/application.properties index 74b2cdfe3b7b..7e805ea4055a 100644 --- a/messaging/src/main/resources/application.properties +++ b/messaging/src/main/resources/application.properties @@ -1,3 +1,28 @@ +# +# This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). +# +# The MIT License +# Copyright © 2014-2022 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + spring.kafka.consumer.auto-offset-reset=earliest spring.kafka.consumer.group-id=messaging diff --git a/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java b/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java index 4fe5b3f1ea40..e403b5509720 100644 --- a/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java +++ b/messaging/src/test/java/com/iluwatar/messaging/MessagingApplicationTests.java @@ -1,13 +1,49 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging; +import com.iluwatar.messaging.kafka.KafkaConsumer; +import com.iluwatar.messaging.kafka.KafkaProducer; +import com.iluwatar.messaging.service.OrderService; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; + @SpringBootTest class MessagingApplicationTests { + @Autowired OrderService orderService; + + /*** + * Simple context test which will load all the IOC beans and properties to validate the spring boot application + */ @Test void contextLoads() { + Assertions.assertNotNull(orderService); } } diff --git a/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java b/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java index 04102e5f5d16..44000564cf72 100644 --- a/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java +++ b/messaging/src/test/java/com/iluwatar/messaging/controller/OrderControllerIntegrationTest.java @@ -1,11 +1,35 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.iluwatar.messaging.model.MenuItemIdAndQuantity; import com.iluwatar.messaging.model.OrderRequest; -import jakarta.servlet.ServletContext; -import org.jetbrains.annotations.NotNull; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +43,7 @@ import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.ResultActions; +import javax.servlet.ServletContext; import java.nio.charset.StandardCharsets; import java.util.List; @@ -29,7 +54,11 @@ @SpringBootTest @AutoConfigureMockMvc @DirtiesContext -@EmbeddedKafka(partitions = 1, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"}) +@EmbeddedKafka( + topics = {"order-topic"}, + partitions = 2, brokerProperties = { + "listeners=PLAINTEXT://localhost:9092", + "auto.create.topics.enable=true"}) public class OrderControllerIntegrationTest { ObjectMapper objectMapper = new ObjectMapper(); @@ -39,10 +68,7 @@ public class OrderControllerIntegrationTest { @Test void shouldPlaceTheOrderAndReturn_200WhenOrderIsOk() throws Exception { - OrderRequest orderRequest = new OrderRequest(); - orderRequest.setConsumerId(1001L); - orderRequest.setRestaurantId(2001L); - orderRequest.setMenuItemIdAndQuantityList(testMenuItems()); + OrderRequest orderRequest = new OrderRequest(1001L, 2001L, testMenuItems()); RequestBuilder requestBuilder = new RequestBuilder() { @Override public MockHttpServletRequest buildRequest(ServletContext servletContext) { @@ -60,6 +86,7 @@ void shouldPlaceTheOrderAndReturn_200WhenOrderIsOk() throws Exception { }; ResultActions resultActions = this.mockMvc.perform(requestBuilder).andExpect(status().isCreated()); + Assertions.assertNotNull(resultActions); } @Test @@ -69,21 +96,18 @@ void shouldPlaceTheOrderAndReturn_400WhenOrderIsInvalid() throws Exception { orderRequest.setMenuItemIdAndQuantityList(testMenuItems()); RequestBuilder requestBuilder = new RequestBuilder() { - @Override public MockHttpServletRequest buildRequest(ServletContext servletContext) { + @SneakyThrows @Override public MockHttpServletRequest buildRequest(ServletContext servletContext) { MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest(); mockHttpServletRequest.setRequestURI("/order/place"); mockHttpServletRequest.setMethod("POST"); - try { - mockHttpServletRequest.setContent(objectMapper.writeValueAsString(orderRequest).getBytes(StandardCharsets.UTF_8)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + mockHttpServletRequest.setContent(objectMapper.writeValueAsString(orderRequest).getBytes(StandardCharsets.UTF_8)); mockHttpServletRequest.setContentType(APPLICATION_JSON_VALUE); return mockHttpServletRequest; } }; ResultActions resultActions = this.mockMvc.perform(requestBuilder).andExpect(status().isBadRequest()); + Assertions.assertNotNull(resultActions); } @Test @@ -109,9 +133,10 @@ void shouldPlaceTheOrderAndReturn_500WhenOrderDoesNotHaveItems() throws Exceptio }; ResultActions resultActions = this.mockMvc.perform(requestBuilder).andExpect(status().isInternalServerError()); + Assertions.assertNotNull(resultActions); } - @NotNull private List testMenuItems() { + private List testMenuItems() { return List.of(new MenuItemIdAndQuantity("CAKE", 1)); } } diff --git a/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java b/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java index eeed502fe6c0..123035be30d8 100644 --- a/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java +++ b/messaging/src/test/java/com/iluwatar/messaging/service/OrderServiceIntegrationTest.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.messaging.service; import com.iluwatar.messaging.exception.ConsumerNotFoundException; @@ -6,7 +30,6 @@ import com.iluwatar.messaging.kafka.KafkaConsumer; import com.iluwatar.messaging.model.MenuItemIdAndQuantity; import com.iluwatar.messaging.model.Order; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -56,8 +79,7 @@ void shouldThrowRestaurantNotFoundException() { void shouldThrowOrderWithZeroItemException() { Assertions.assertThrows(OrderWithZeroItemException.class, ()->orderService.createOrder(1001L, 2001, null)); } - - @NotNull private List testMenuItems() { + private List testMenuItems() { return List.of(new MenuItemIdAndQuantity("CAKE", 1)); }