diff --git a/transaction-service/pom.xml b/transaction-service/pom.xml index 80f2de9b9fa5a392dadbda4d2c128488678e0e2e..9ad106cb0898ed75f25eb1d51713a937106de375 100644 --- a/transaction-service/pom.xml +++ b/transaction-service/pom.xml @@ -110,6 +110,11 @@ <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-jms</artifactId> + <version>6.1.6</version> + </dependency> </dependencies> <build> diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java b/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java index e4fab667951435f05abd5b56dc29dfd7cec727a6..815d5f4246d635f58355c2ad720ca6ec9407b795 100644 --- a/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java +++ b/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java @@ -2,6 +2,7 @@ package cz.muni.fi.obs.data.dbo; public enum TransactionState { + PROCESSING, SUCCESSFUL, FAILED; } diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java b/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java index 41696ddac65d28d0996e5168e529485a46bf6c41..35d0944630090d53fdd16f3f2ea25ab6cb399da4 100644 --- a/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java +++ b/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java @@ -5,6 +5,7 @@ import cz.muni.fi.obs.api.TransactionCreateDto; import cz.muni.fi.obs.data.dbo.AccountDbo; import cz.muni.fi.obs.data.dbo.TransactionDbo; import cz.muni.fi.obs.exceptions.ResourceNotFoundException; +import cz.muni.fi.obs.jms.JmsProducer; import cz.muni.fi.obs.service.AccountService; import cz.muni.fi.obs.service.TransactionService; import lombok.extern.slf4j.Slf4j; @@ -22,11 +23,13 @@ public class TransactionManagementFacade { private final TransactionService transactionService; private final AccountService accountService; + private final JmsProducer jmsProducer; @Autowired - public TransactionManagementFacade(TransactionService transactionService, AccountService accountService) { + public TransactionManagementFacade(TransactionService transactionService, AccountService accountService, JmsProducer jmsProducer) { this.transactionService = transactionService; this.accountService = accountService; + this.jmsProducer = jmsProducer; } public Optional<TransactionDbo> getTransactionById(String id) { diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java new file mode 100644 index 0000000000000000000000000000000000000000..6061cf1dfd8932ac732d1d3bc3bfe106c62c0538 --- /dev/null +++ b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java @@ -0,0 +1,27 @@ +package cz.muni.fi.obs.jms; + +import cz.muni.fi.obs.service.TransactionService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +import static cz.muni.fi.obs.jms.JmsProducer.TRANSACTION_QUEUE_NAME; + +@Component +@Slf4j +public class JmsConsumer { + + private final TransactionService transactionService; + + @Autowired + public JmsConsumer(TransactionService transactionService) { + this.transactionService = transactionService; + } + + @JmsListener(destination = TRANSACTION_QUEUE_NAME, concurrency = "1-4") + public void listenTransactions(String transactionId) { + log.info("Executing transaction with id: " + transactionId); + transactionService.executeTransaction(transactionId); + } +} diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java new file mode 100644 index 0000000000000000000000000000000000000000..e9106f873b2a7d98cdb1bc9a429f850870d8806d --- /dev/null +++ b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java @@ -0,0 +1,25 @@ +package cz.muni.fi.obs.jms; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class JmsProducer { + + private final JmsTemplate jmsTemplate; + public final static String TRANSACTION_QUEUE_NAME = "transactions"; + + + @Autowired + public JmsProducer(JmsTemplate jmsTemplate) { + this.jmsTemplate = jmsTemplate; + } + + public void sendMessage(String transactionId) { + log.info("Attempting to send message: " + transactionId); + jmsTemplate.convertAndSend(TRANSACTION_QUEUE_NAME, transactionId); + } +} diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java b/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java index 8671edb9107d1977949053dcb70cd61676ca8989..a8e878134969919ac1430b86c7b4154a352f3c14 100644 --- a/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java +++ b/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java @@ -22,6 +22,7 @@ import java.util.Optional; import java.util.UUID; import static cz.muni.fi.obs.data.dbo.TransactionState.FAILED; +import static cz.muni.fi.obs.data.dbo.TransactionState.PROCESSING; import static cz.muni.fi.obs.data.dbo.TransactionState.SUCCESSFUL; @Slf4j @@ -71,29 +72,37 @@ public class TransactionService { AccountDbo depositsToAccount = accountRepository.findAccountDboByAccountNumber(transaction.depositsToAccountNumber()) .orElseThrow(() -> new ResourceNotFoundException(AccountDbo.class, transaction.depositsToAccountNumber())); - CurrencyExchangeRequest request = CurrencyExchangeRequest.builder() - .from(transaction.withdrawsFromAccountNumber()) - .to(transaction.depositsToAccountNumber()) - .amount(transaction.withdrawAmount()) - .build(); - - CurrencyExchangeResult exchangeResult = callCurrencyClient(request); - - var transactionDbo = TransactionDbo.builder() + TransactionDbo transactionDbo = TransactionDbo.builder() .id(UUID.randomUUID().toString()) .withdrawsFrom(withdrawsFromAccount) .note(transaction.note()) .depositsTo(depositsToAccount) - .depositAmount(exchangeResult.destAmount()) .withdrawAmount(transaction.withdrawAmount()) .variableSymbol(transaction.variableSymbol()) - .conversionRate(exchangeResult.exchangeRate()) - .transactionState(computeTransactionState(withdrawsFromAccount.getId(), transaction.withdrawAmount())) + .transactionState(PROCESSING) .build(); return repository.save(transactionDbo); } + public void executeTransaction(String transactionId) { + TransactionDbo transaction = repository.findById(transactionId) + .orElseThrow(() -> new ResourceNotFoundException(TransactionDbo.class, transactionId)); + + CurrencyExchangeRequest request = CurrencyExchangeRequest.builder() + .from(transaction.getWithdrawsFrom().getCurrencyCode()) + .to(transaction.getDepositsTo().getCurrencyCode()) + .amount(transaction.getWithdrawAmount()) + .build(); + + CurrencyExchangeResult exchangeResult = callCurrencyClient(request); + + transaction.setConversionRate(exchangeResult.exchangeRate()); + transaction.setDepositAmount(exchangeResult.destAmount()); + transaction.setTransactionState(computeTransactionState(transaction.getWithdrawsFrom().getId(), transaction.getWithdrawAmount())); + repository.save(transaction); + } + private TransactionState computeTransactionState(String id, BigDecimal withdrawAmount) { return calculateAccountBalance(id).compareTo(withdrawAmount) > 0 ? SUCCESSFUL : FAILED; } diff --git a/transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql b/transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql new file mode 100644 index 0000000000000000000000000000000000000000..6074b1721ff3383639df96cf98250d7532997ae6 --- /dev/null +++ b/transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql @@ -0,0 +1,4 @@ +ALTER TABLE transactions + ALTER COLUMN deposited_amount drop not null; +ALTER TABLE transactions + ALTER COLUMN conversion_rate drop not null;