diff --git a/Oracle_CQRS/pom.xml b/Oracle_CQRS/pom.xml index 9a78d3382..d4766b07b 100644 --- a/Oracle_CQRS/pom.xml +++ b/Oracle_CQRS/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.4.5 + 3.4.6 Oracle_CQRS @@ -14,8 +14,8 @@ 21 1.18.38 2.8.6 - 25.1.0 - 25.1.0 + 25.2.0 + 25.2.0 diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/aggregates/AccountAggregate.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/aggregates/AccountAggregate.java index 07ba9bb5a..7a1a7540a 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/aggregates/AccountAggregate.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/aggregates/AccountAggregate.java @@ -1,8 +1,8 @@ package org.example.oracle.cqrs.command.aggregates; import jakarta.transaction.Transactional; -import lombok.*; +import lombok.Getter; import org.example.oracle.cqrs.command.commands.*; import org.example.oracle.cqrs.common.events.*; import org.example.oracle.cqrs.command.producers.EventProducer; @@ -37,45 +37,8 @@ public AccountAggregate(EventProducer eventProducer, EventStoreRepository eventS @JmsListener(destination = "${txeventq.queue.commands.name}", id = "sampleCommand") void handleCommand(BaseCommand command) { - - BaseEvent event; - - switch (command) { - case CreateAccountCommand createAccountCommand -> { - System.out.println("Handling create: " + command); - if (createAccountCommand.getInitialBalance() < 0) - throw new IllegalArgumentException("Initial balance is negative"); - - event = new AccountCreatedEvent(UUID.randomUUID().toString(), createAccountCommand.getInitialBalance(), createAccountCommand.getCurrency(), AccountStatus.CREATED, createAccountCommand.getAccountId()); - - } - case DebitAccountCommand debitAccountCommand -> { - System.out.println("Handling debit: " + command); - if (debitAccountCommand.getAmount() < 0) throw new IllegalArgumentException("Amount is negative"); - - event = new AccountDebitedEvent(UUID.randomUUID().toString(), debitAccountCommand.getAccountId(), debitAccountCommand.getCurrency(), debitAccountCommand.getAmount()); - - - } - case CreditAccountCommand creditAccountCommand -> { - System.out.println("Handling debit: " + command); - if (creditAccountCommand.getAmount() < 0) throw new IllegalArgumentException("Amount is negative"); - - event = new AccountCreditedEvent(UUID.randomUUID().toString(), creditAccountCommand.getCurrency(), creditAccountCommand.getAmount(), creditAccountCommand.getAccountId()); - - - } - case UpdateAccountStatusCommand updateAccountStatusCommand -> { - System.out.println("Handling debit: " + command); - event = new AccountStatusUpdatedEvent(UUID.randomUUID().toString(), updateAccountStatusCommand.getAccountStatus(), updateAccountStatusCommand.getAccountId()); - - } - - default -> throw new IllegalStateException("Unexpected value: " + command); - } - + BaseEvent event = command.createEvent(); eventProducer.enqueue(event); eventStoreRepository.save(event); - } } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/BaseCommand.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/BaseCommand.java index 540595de7..45a239f2c 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/BaseCommand.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/BaseCommand.java @@ -3,11 +3,13 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.example.oracle.cqrs.common.events.BaseEvent; @AllArgsConstructor @NoArgsConstructor -public class BaseCommand{ +public abstract class BaseCommand{ @Getter private T id; + public abstract BaseEvent createEvent(); } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreateAccountCommand.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreateAccountCommand.java index 2494870c6..505c5e1f2 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreateAccountCommand.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreateAccountCommand.java @@ -1,8 +1,15 @@ package org.example.oracle.cqrs.command.commands; -import lombok.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.example.oracle.cqrs.common.enums.AccountStatus; +import org.example.oracle.cqrs.common.events.AccountCreatedEvent; +import org.example.oracle.cqrs.common.events.BaseEvent; -@Getter @NoArgsConstructor +import java.util.UUID; + +@Getter +@NoArgsConstructor public class CreateAccountCommand extends BaseCommand { private double initialBalance; private String currency; @@ -14,4 +21,13 @@ public CreateAccountCommand(String id, double initialBalance, String currency, S this.currency = currency; this.accountId = accountId; } + + @Override + public BaseEvent createEvent() { + System.out.println("Handling create: " + this); + if (this.getInitialBalance() < 0) + throw new IllegalArgumentException("Initial balance is negative"); + + return new AccountCreatedEvent(UUID.randomUUID().toString(), initialBalance, currency, AccountStatus.CREATED, accountId); + } } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreditAccountCommand.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreditAccountCommand.java index ee7c80910..3ce7d0c50 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreditAccountCommand.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/CreditAccountCommand.java @@ -3,6 +3,10 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import org.example.oracle.cqrs.common.events.AccountCreditedEvent; +import org.example.oracle.cqrs.common.events.BaseEvent; + +import java.util.UUID; @Getter @NoArgsConstructor @@ -17,4 +21,13 @@ public CreditAccountCommand(String id, String accountId, double amount, String c this.amount = amount; this.currency = currency; } + + @Override + public BaseEvent createEvent() { + System.out.println("Handling debit: " + this); + if (amount < 0) throw new IllegalArgumentException("Amount is negative"); + + return new AccountCreditedEvent(UUID.randomUUID().toString(), currency, amount, accountId); + + } } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/DebitAccountCommand.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/DebitAccountCommand.java index dc62aec61..4f78aac1d 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/DebitAccountCommand.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/DebitAccountCommand.java @@ -1,6 +1,11 @@ package org.example.oracle.cqrs.command.commands; -import lombok.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.example.oracle.cqrs.common.events.AccountDebitedEvent; +import org.example.oracle.cqrs.common.events.BaseEvent; + +import java.util.UUID; @Getter @NoArgsConstructor @@ -16,4 +21,11 @@ public DebitAccountCommand(String id, String accountId, double amount, String cu this.currency = currency; } + @Override + public BaseEvent createEvent() { + System.out.println("Handling debit: " + this); + if (amount < 0) throw new IllegalArgumentException("Amount is negative"); + return new AccountDebitedEvent(UUID.randomUUID().toString(), accountId, currency, amount); + + } } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/UpdateAccountStatusCommand.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/UpdateAccountStatusCommand.java index c16913eae..fd8cca47d 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/UpdateAccountStatusCommand.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/commands/UpdateAccountStatusCommand.java @@ -3,6 +3,10 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.example.oracle.cqrs.common.enums.AccountStatus; +import org.example.oracle.cqrs.common.events.AccountStatusUpdatedEvent; +import org.example.oracle.cqrs.common.events.BaseEvent; + +import java.util.UUID; @Getter @NoArgsConstructor @@ -15,4 +19,10 @@ public UpdateAccountStatusCommand(String id, String accountId, AccountStatus acc this.accountId = accountId; this.accountStatus = accountStatus; } + + @Override + public BaseEvent createEvent() { + System.out.println("Handling update account : " + this); + return new AccountStatusUpdatedEvent(UUID.randomUUID().toString(), accountStatus, accountId); + } } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/controlles/AccountCommandRest.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/controlles/AccountCommandRest.java index 95839fbfd..f7391ab06 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/controlles/AccountCommandRest.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/command/controlles/AccountCommandRest.java @@ -13,10 +13,19 @@ import org.example.oracle.cqrs.common.Dtos.DebitAccountDTO; import org.example.oracle.cqrs.common.Dtos.UpdateAccountStatusDTO; import org.example.oracle.cqrs.common.events.BaseEvent; -import org.springframework.http.HttpStatus; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; import java.util.List; import java.util.UUID; @@ -26,38 +35,41 @@ public class AccountCommandRest { private CommandsProducer commandsProducer; private EventStoreRepository eventStoreRepository; + private String queryBsedUrl ; - AccountCommandRest(CommandsProducer commandsProducer, EventStoreRepository eventStoreRepository) { + AccountCommandRest(CommandsProducer commandsProducer, EventStoreRepository eventStoreRepository, @Value("${query.base.url}") String queryBsedUrl) { this.commandsProducer = commandsProducer; this.eventStoreRepository = eventStoreRepository; + this.queryBsedUrl = queryBsedUrl; } @PostMapping("/create") public ResponseEntity createAccount(@Valid @RequestBody CreateAccountDTO request) { String accountId = UUID.randomUUID().toString(); commandsProducer.enqueue(new CreateAccountCommand(UUID.randomUUID().toString(), request.getInitialBalance(), request.getCurrency(), accountId)); - - return ResponseEntity.status(HttpStatus.ACCEPTED).header("Location", "/api/queries/status/" + accountId).build(); + URI location = getGetQueryUri(accountId); + return ResponseEntity.created(location).build(); } @PostMapping("/debit") public ResponseEntity debitAccount(@Valid @RequestBody DebitAccountDTO request) { commandsProducer.enqueue(new DebitAccountCommand(UUID.randomUUID().toString(), request.getAccountId(), request.getAmount(), request.getCurrency())); - - return ResponseEntity.status(HttpStatus.ACCEPTED).header("Location", "/api/queries/" + request.getAccountId()).build(); + URI location = getGetQueryUri(request.getAccountId()); + return ResponseEntity.created(location).build(); } @PostMapping("/credit") public ResponseEntity creditAccount(@Valid @RequestBody CreditAccountDTO request) { commandsProducer.enqueue(new CreditAccountCommand(UUID.randomUUID().toString(), request.getAccountId(), request.getAmount(), request.getCurrency())); - - return ResponseEntity.status(HttpStatus.ACCEPTED).header("Location", "/api/queries/" + request.getAccountId()).build(); + URI location = getGetQueryUri(request.getAccountId()); + return ResponseEntity.created(location).build(); } @PutMapping("/updateStatus") public ResponseEntity updateStatus(@Valid @RequestBody UpdateAccountStatusDTO request) { commandsProducer.enqueue(new UpdateAccountStatusCommand(UUID.randomUUID().toString(), request.getAccountId(), request.getAccountStatus())); - return ResponseEntity.status(HttpStatus.ACCEPTED).header("Location", "/api/queries/status/" + request.getAccountId()).build(); + URI location = getGetQueryUri(request.getAccountId()); + return ResponseEntity.created(location).build(); } @@ -71,5 +83,13 @@ public String exceptionHandler(Exception exception) { return exception.getMessage(); } + private URI getGetQueryUri(String accountId) { + URI location = UriComponentsBuilder.fromHttpUrl(queryBsedUrl) + .path("/" + accountId) + .build() + .toUri(); + return location; + } + } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/CreateAccountDTO.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/CreateAccountDTO.java index 8ab009b5f..89f586530 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/CreateAccountDTO.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/CreateAccountDTO.java @@ -2,7 +2,10 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; @Getter @Setter diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/UpdateAccountStatusDTO.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/UpdateAccountStatusDTO.java index c8bf8906d..b495d57a0 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/UpdateAccountStatusDTO.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/common/Dtos/UpdateAccountStatusDTO.java @@ -2,6 +2,7 @@ package org.example.oracle.cqrs.common.Dtos; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,6 +12,6 @@ public class UpdateAccountStatusDTO { @NotBlank private String accountId ; - @NotBlank + @NotNull private AccountStatus accountStatus ; } diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/controller/AccountQueryRest.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/controller/AccountQueryRest.java index 467afb9c2..07377f06e 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/controller/AccountQueryRest.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/controller/AccountQueryRest.java @@ -4,7 +4,10 @@ import org.example.oracle.cqrs.query.entities.Account; import org.example.oracle.cqrs.query.repositories.AccountRepository; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.List; diff --git a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/entities/Account.java b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/entities/Account.java index fdd2912a2..b42d5627e 100644 --- a/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/entities/Account.java +++ b/Oracle_CQRS/src/main/java/org/example/oracle/cqrs/query/entities/Account.java @@ -4,7 +4,10 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.Id; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import org.example.oracle.cqrs.common.enums.AccountStatus; import java.util.Date; diff --git a/Oracle_CQRS/src/main/resources/application.properties b/Oracle_CQRS/src/main/resources/application.properties index df301c7ce..ccfcfb58d 100644 --- a/Oracle_CQRS/src/main/resources/application.properties +++ b/Oracle_CQRS/src/main/resources/application.properties @@ -1,2 +1,3 @@ txeventq.queue.commands.name=${txeventq:commandsqueue} -txeventq.queue.events.name=${txeventq:eventsqueue} \ No newline at end of file +txeventq.queue.events.name=${txeventq:eventsqueue} +query.base.url=http://localhost:8081/api/queries