From 898095b82f57298201b030ad0ecf5a669dd24bd9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20Pit=C3=A1k?= <xpitak@fi.muni.cz>
Date: Fri, 5 Apr 2024 01:26:30 +0200
Subject: [PATCH] Create artefact with shared implementations, custom
 exceptions, handling custom exceptions with overriding responses

---
 infrastructure/pom.xml                        | 32 ++++++++++++++
 .../banking/exception/CustomException.java    | 33 +++++++++++++++
 .../exception/CustomExceptionHandler.java     | 20 +++++++++
 .../exception/EntityNotFoundException.java    | 42 +++++++++++++++++++
 .../pa165/banking/exception/ServerError.java  | 40 ++++++++++++++++++
 .../exception/UnexpectedValueException.java   | 41 ++++++++++++++++++
 .../UnsupportedDataTypeException.java         | 32 ++++++++++++++
 .../pa165/banking/security/AuthService.java   |  5 +++
 transaction-processor/pom.xml                 | 11 +++++
 .../configuration/BeanRegistry.java           | 15 +++++++
 .../application/facade/TransactionFacade.java |  6 ++-
 .../messaging/ProcessProducer.java            | 21 ++++++++--
 .../service/TransactionService.java           |  6 +--
 .../domain/messaging/MessageProducer.java     |  4 +-
 .../domain/messaging/ProcessRequest.java      |  9 ++++
 .../domain/money/CurrencyConverter.java       |  3 +-
 .../domain/process/ProcessFactory.java        |  2 +-
 .../process/handler/DepositHandler.java       |  3 +-
 .../process/handler/ProcessHandler.java       |  8 +++-
 .../handler/ProcessHandlerGateway.java        |  3 +-
 .../process/handler/WithdrawHandler.java      |  5 ++-
 21 files changed, 320 insertions(+), 21 deletions(-)
 create mode 100644 infrastructure/pom.xml
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomException.java
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomExceptionHandler.java
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/exception/EntityNotFoundException.java
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/exception/ServerError.java
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnexpectedValueException.java
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnsupportedDataTypeException.java
 create mode 100644 infrastructure/src/main/java/cz/muni/pa165/banking/security/AuthService.java
 create mode 100644 transaction-processor/src/main/java/cz/muni/pa165/banking/application/configuration/BeanRegistry.java

diff --git a/infrastructure/pom.xml b/infrastructure/pom.xml
new file mode 100644
index 0000000..ed05eb4
--- /dev/null
+++ b/infrastructure/pom.xml
@@ -0,0 +1,32 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.2.4</version>
+        <relativePath/>
+    </parent>
+    
+    
+    <groupId>cz.muni.pa165.banking</groupId>
+    <artifactId>infrastructure</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>21</maven.compiler.source>
+        <maven.compiler.target>21</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <!--  Only exact dependencies to eliminate transitive dependencies  -->
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomException.java b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomException.java
new file mode 100644
index 0000000..aa863e1
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomException.java
@@ -0,0 +1,33 @@
+package cz.muni.pa165.banking.exception;
+
+import org.springframework.http.HttpStatus;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public abstract class CustomException extends RuntimeException {
+
+    public final Map<String, Object> getBody() {
+        Map<String, Object> body = new LinkedHashMap<>();
+        body.put("status", getStatus());
+        body.put("code", getStatus().value());
+        body.put("exception", this.getClass().getSimpleName());
+        body.put("message", getExceptionMessage());
+        body.put("cause", getExceptionCause());
+        
+        if (getDetail() != null) {
+            body.put("detail", getDetail());
+        }
+        
+        return body;
+    }
+    
+    public abstract HttpStatus getStatus();
+    
+    abstract String getExceptionMessage();
+    
+    abstract String getExceptionCause();
+    
+    abstract Object getDetail();
+    
+}
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomExceptionHandler.java b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomExceptionHandler.java
new file mode 100644
index 0000000..7defee0
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/CustomExceptionHandler.java
@@ -0,0 +1,20 @@
+package cz.muni.pa165.banking.exception;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+/**
+ * Handles custom exceptions thrown in application. The handler overrides the controller return value,
+ * evaluating the assigned status code and response body. 
+ * The response body is evaluated as a JSON object, containing defined information such as the status code, 
+ * exception type, message, cause and an optional detail regarding the exception.
+ */
+public class CustomExceptionHandler {
+
+    @ExceptionHandler(CustomException.class)
+    public ResponseEntity<Object> handleEntityNotFound(CustomException ex) {
+        return new ResponseEntity<>(ex.getBody(), ex.getStatus());
+    }
+    
+}
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/exception/EntityNotFoundException.java b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/EntityNotFoundException.java
new file mode 100644
index 0000000..a7c55b3
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/EntityNotFoundException.java
@@ -0,0 +1,42 @@
+package cz.muni.pa165.banking.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class EntityNotFoundException extends CustomException {
+    
+    private final String cause;
+
+    private final Object detail;
+
+    public EntityNotFoundException(String cause) {
+        this.cause = cause;
+        detail = null;
+    }
+
+    public EntityNotFoundException(String cause, Object detail) {
+        this.cause = cause;
+        this.detail = detail;
+    }
+
+    @Override
+    public HttpStatus getStatus() {
+        return HttpStatus.NOT_FOUND;
+    }
+
+    @Override
+    String getExceptionMessage() {
+        return "Entity not present in repository";
+    }
+
+    @Override
+    String getExceptionCause() {
+        return cause;
+    }
+
+    @Override
+    Object getDetail() {
+        return detail;
+    }
+
+
+}
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/exception/ServerError.java b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/ServerError.java
new file mode 100644
index 0000000..701242d
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/ServerError.java
@@ -0,0 +1,40 @@
+package cz.muni.pa165.banking.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class ServerError extends CustomException {
+    
+    private final String cause;
+
+    private final Object detail;
+
+    public ServerError(String cause) {
+        this.cause = cause;
+        detail = null;
+    }
+
+    public ServerError(String cause, Object detail) {
+        this.cause = cause;
+        this.detail = detail;
+    }
+    @Override
+    public HttpStatus getStatus() {
+        return HttpStatus.INTERNAL_SERVER_ERROR;
+    }
+
+    @Override
+    String getExceptionMessage() {
+        return "Internal Server Error";
+    }
+
+    @Override
+    String getExceptionCause() {
+        return cause;
+    }
+
+    @Override
+    Object getDetail() {
+        return detail;
+    }
+
+}
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnexpectedValueException.java b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnexpectedValueException.java
new file mode 100644
index 0000000..201cfeb
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnexpectedValueException.java
@@ -0,0 +1,41 @@
+package cz.muni.pa165.banking.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class UnexpectedValueException extends CustomException {
+    
+    private final String cause;
+    
+    private final Object detail;
+
+    public UnexpectedValueException(String cause, Object detail) {
+        this.cause = cause;
+        this.detail = detail;
+    }
+
+    public UnexpectedValueException(String cause) {
+        this.cause = cause;
+        this.detail = null;
+    }
+
+    @Override
+    public HttpStatus getStatus() {
+        return HttpStatus.CONFLICT;
+    }
+
+    @Override
+    String getExceptionMessage() {
+        return "Unexpected value state";
+    }
+
+    @Override
+    String getExceptionCause() {
+        return cause;
+    }
+
+    @Override
+    Object getDetail() {
+        return detail;
+    }
+
+}
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnsupportedDataTypeException.java b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnsupportedDataTypeException.java
new file mode 100644
index 0000000..68ca401
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/exception/UnsupportedDataTypeException.java
@@ -0,0 +1,32 @@
+package cz.muni.pa165.banking.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class UnsupportedDataTypeException extends CustomException {
+    
+    private final String cause;
+
+    public UnsupportedDataTypeException(String cause) {
+        this.cause = cause;
+    }
+
+    @Override
+    public HttpStatus getStatus() {
+        return HttpStatus.BAD_REQUEST;
+    }
+
+    @Override
+    String getExceptionMessage() {
+        return "Unsupported data type";
+    }
+
+    @Override
+    String getExceptionCause() {
+        return cause;
+    }
+
+    @Override
+    Object getDetail() {
+        return null;
+    }
+}
diff --git a/infrastructure/src/main/java/cz/muni/pa165/banking/security/AuthService.java b/infrastructure/src/main/java/cz/muni/pa165/banking/security/AuthService.java
new file mode 100644
index 0000000..2915be0
--- /dev/null
+++ b/infrastructure/src/main/java/cz/muni/pa165/banking/security/AuthService.java
@@ -0,0 +1,5 @@
+package cz.muni.pa165.banking.security;
+
+// TODO Milestone2
+public class AuthService {
+}
diff --git a/transaction-processor/pom.xml b/transaction-processor/pom.xml
index b5c4c47..153a12c 100644
--- a/transaction-processor/pom.xml
+++ b/transaction-processor/pom.xml
@@ -21,6 +21,11 @@
         <maven.compiler.target>21</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         
+        <!--    External project artifact versions    -->
+        <banking-infrastructure.version>1.0-SNAPSHOT</banking-infrastructure.version>
+        <banking-openapi.version>1.0-SNAPSHOT</banking-openapi.version>
+        
+        
         <spring.version>3.2.4</spring.version>
         <openapi-generator.version>6.6.0</openapi-generator.version>
         <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
@@ -28,6 +33,12 @@
     </properties>
     
     <dependencies>
+        <dependency>
+            <groupId>cz.muni.pa165.banking</groupId>
+            <artifactId>infrastructure</artifactId>
+            <version>${banking-infrastructure.version}</version>
+        </dependency>
+        
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/configuration/BeanRegistry.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/configuration/BeanRegistry.java
new file mode 100644
index 0000000..b9f7585
--- /dev/null
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/configuration/BeanRegistry.java
@@ -0,0 +1,15 @@
+package cz.muni.pa165.banking.application.configuration;
+
+import cz.muni.pa165.banking.exception.CustomExceptionHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class BeanRegistry {
+    
+    @Bean
+    public CustomExceptionHandler exceptionHandler() {
+        return new CustomExceptionHandler();
+    }
+    
+}
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/facade/TransactionFacade.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/facade/TransactionFacade.java
index 0d96a02..f92c60d 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/facade/TransactionFacade.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/facade/TransactionFacade.java
@@ -4,11 +4,15 @@ import cz.muni.pa165.banking.application.mapper.DtoMapper;
 import cz.muni.pa165.banking.application.service.TransactionService;
 import cz.muni.pa165.banking.domain.process.Process;
 import cz.muni.pa165.banking.domain.transaction.Transaction;
+import cz.muni.pa165.banking.exception.EntityNotFoundException;
 import cz.muni.pa165.banking.transaction.processor.dto.ProcessDto;
 import cz.muni.pa165.banking.transaction.processor.dto.TransactionDto;
+import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 
-@Service
+import java.util.List;
+
+@Component
 public class TransactionFacade {
 
     private final TransactionService service;
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/messaging/ProcessProducer.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/messaging/ProcessProducer.java
index b091645..44cdc38 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/messaging/ProcessProducer.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/messaging/ProcessProducer.java
@@ -1,12 +1,14 @@
 package cz.muni.pa165.banking.application.messaging;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import cz.muni.pa165.banking.domain.messaging.MessageProducer;
 import cz.muni.pa165.banking.domain.messaging.ProcessRequest;
+import cz.muni.pa165.banking.exception.ServerError;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import java.util.Map;
+
 @Service
 public class ProcessProducer implements MessageProducer {
     
@@ -24,9 +26,20 @@ public class ProcessProducer implements MessageProducer {
 
     
     @Override
-    public void send(ProcessRequest data) throws JsonProcessingException {
-        String dataAsJsonString = mapper.writeValueAsString(data);
-//        template.convertAndSend(EXCHANGE_NAME, "", data); 
+    public void send(ProcessRequest data) {
+        String dataAsJsonString;
+        try {
+            dataAsJsonString = mapper.writeValueAsString(data);
+        } catch (Exception e) {
+            throw new ServerError(
+                    "Unable to map ProcessRequest to String",
+                    Map.of(
+                            "causeLocation", "cz.muni.pa165.banking.application.messaging.ProcessProducer.send",
+                            "invalidObject", data.toString()
+                    )
+            );
+        }
+//        template.convertAndSend(EXCHANGE_NAME, "", dataAsJsonString); 
     }
     
 }
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionService.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionService.java
index 3376d51..51810f0 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionService.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionService.java
@@ -27,11 +27,7 @@ public class TransactionService {
     @Transactional(rollbackFor = Exception.class)
     public Process createProcessForTransaction(Transaction newTransaction) {
         ProcessFactory factory = new ProcessFactory(processTransactionRepository, processRepository);
-        try {
-            return factory.create(newTransaction, processProducer);
-        } catch (Exception e) {
-            throw new RuntimeException(e.getMessage());
-        }
+        return factory.create(newTransaction, processProducer);
     }
 
 }
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/MessageProducer.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/MessageProducer.java
index f5f870b..1359e6e 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/MessageProducer.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/MessageProducer.java
@@ -1,9 +1,7 @@
 package cz.muni.pa165.banking.domain.messaging;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-
 public interface MessageProducer {
     
-    void send(ProcessRequest data) throws JsonProcessingException;    
+    void send(ProcessRequest data);    
     
 }
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/ProcessRequest.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/ProcessRequest.java
index 79bf529..dece456 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/ProcessRequest.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/messaging/ProcessRequest.java
@@ -5,4 +5,13 @@ import cz.muni.pa165.banking.domain.transaction.TransactionType;
 import java.util.UUID;
 
 public record ProcessRequest(UUID uuid, TransactionType type) {
+
+    @Override
+    public String toString() {
+        return "ProcessRequest{" +
+                "uuid=" + uuid +
+                ", type=" + type +
+                '}';
+    }
+    
 }
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/money/CurrencyConverter.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/money/CurrencyConverter.java
index b78bbba..e3b709e 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/money/CurrencyConverter.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/money/CurrencyConverter.java
@@ -1,6 +1,7 @@
 package cz.muni.pa165.banking.domain.money;
 
 import cz.muni.pa165.banking.domain.money.exchange.ExchangeRateService;
+import cz.muni.pa165.banking.exception.UnsupportedDataTypeException;
 
 import java.math.BigDecimal;
 import java.util.Currency;
@@ -21,7 +22,7 @@ public class CurrencyConverter {
      */
     public BigDecimal convertTo(Currency target, Money amount) {
         if (!Currency.getAvailableCurrencies().contains(target)) {
-            throw new RuntimeException("Unsupported target currency");
+            throw new UnsupportedDataTypeException("Unsupported target currency");
         }
         BigDecimal rate = BigDecimal.ONE;
         if (!amount.getCurrency().equals(target)) {
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java
index 09613c5..a30ddd2 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java
@@ -19,7 +19,7 @@ public class ProcessFactory {
     }
 
 
-    public Process create(Transaction transaction, MessageProducer messageProducer) throws Exception {
+    public Process create(Transaction transaction, MessageProducer messageProducer) {
         Process newProcess = new Process();
         processRepository.save(newProcess);
 
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/DepositHandler.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/DepositHandler.java
index 49ff9b9..10559e6 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/DepositHandler.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/DepositHandler.java
@@ -6,6 +6,7 @@ import cz.muni.pa165.banking.domain.process.ProcessTransaction;
 import cz.muni.pa165.banking.domain.process.repository.HandlerMBeanRepository;
 import cz.muni.pa165.banking.domain.process.repository.ProcessRepository;
 import cz.muni.pa165.banking.domain.remote.AccountService;
+import cz.muni.pa165.banking.exception.EntityNotFoundException;
 
 import java.math.BigDecimal;
 import java.util.Currency;
@@ -23,7 +24,7 @@ class DepositHandler extends ProcessHandler {
         Account account = processTransaction.getSource();
         AccountService accountService = beans.accountService();
         if (!accountService.isValid(account)) {
-            throw new RuntimeException(
+            throw new EntityNotFoundException(
                     String.format("Account with number {%s} does not exist", account.getAccountNumber())
             );
         }
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandler.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandler.java
index 8b61448..51df0c4 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandler.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandler.java
@@ -6,6 +6,7 @@ import cz.muni.pa165.banking.domain.process.repository.HandlerMBeanRepository;
 import cz.muni.pa165.banking.domain.process.repository.ProcessRepository;
 import cz.muni.pa165.banking.domain.process.status.Status;
 import cz.muni.pa165.banking.domain.process.status.StatusInformation;
+import cz.muni.pa165.banking.exception.UnexpectedValueException;
 
 import java.time.Instant;
 import java.util.UUID;
@@ -39,10 +40,13 @@ abstract class ProcessHandler {
 
     private void validateProcess(Process process) {
         if (process.getStatus().equals(Status.FAILED)) {
-            throw new RuntimeException("Process already finalized, ended with failure: " + process.getStatusInformation());
+            throw new UnexpectedValueException(
+                    "Process already closed, ended with failure",
+                    "Failure information: " + process.getStatusInformation()
+            );
         }
         if (process.getStatus().equals(Status.PROCESSED)) {
-            throw new RuntimeException("Process already finalized");
+            throw new UnexpectedValueException("Process already finalized, ended successfully", process.getStatusInformation());
         }
     }
 
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandlerGateway.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandlerGateway.java
index 2cbe773..4b7dd6f 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandlerGateway.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/ProcessHandlerGateway.java
@@ -3,6 +3,7 @@ package cz.muni.pa165.banking.domain.process.handler;
 import cz.muni.pa165.banking.domain.process.repository.HandlerMBeanRepository;
 import cz.muni.pa165.banking.domain.process.repository.ProcessRepository;
 import cz.muni.pa165.banking.domain.transaction.TransactionType;
+import cz.muni.pa165.banking.exception.EntityNotFoundException;
 
 import java.util.UUID;
 
@@ -10,7 +11,7 @@ public class ProcessHandlerGateway {
 
     public void handle(UUID processUuid, TransactionType type, ProcessRepository repository, HandlerMBeanRepository beans) {
         if (!repository.idExists(processUuid.toString())) {
-            throw new RuntimeException(String.format("Process with uuid {%s} not found", processUuid));
+            throw new EntityNotFoundException(String.format("Process with uuid {%s} not found", processUuid));
         }
         
         ProcessHandler handler = switch (type) {
diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/WithdrawHandler.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/WithdrawHandler.java
index 124edfe..540bab5 100644
--- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/WithdrawHandler.java
+++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/handler/WithdrawHandler.java
@@ -7,6 +7,7 @@ import cz.muni.pa165.banking.domain.process.ProcessTransaction;
 import cz.muni.pa165.banking.domain.process.repository.HandlerMBeanRepository;
 import cz.muni.pa165.banking.domain.process.repository.ProcessRepository;
 import cz.muni.pa165.banking.domain.remote.AccountService;
+import cz.muni.pa165.banking.exception.EntityNotFoundException;
 
 import java.math.BigDecimal;
 import java.util.Currency;
@@ -24,14 +25,14 @@ public class WithdrawHandler extends ProcessHandler {
         Account account = processTransaction.getSource();
         AccountService accountService = beans.accountService();
         if (!accountService.isValid(account)) {
-            throw new RuntimeException(
+            throw new EntityNotFoundException(
                     String.format("Account with number {%s} does not exist", account.getAccountNumber())
             );
         }
 
         Money money = processTransaction.getAmount();
         if (!accountService.accountHasSufficientFunds(account, money.getAmount())) {
-            throw new RuntimeException(
+            throw new EntityNotFoundException(
                     String.format(
                             "Account with number {%s} does not have sufficient funds for withdrawal of %s %s",
                             account.getAccountNumber(),
-- 
GitLab