source service impl
This commit is contained in:
@@ -2,8 +2,11 @@ package com.amaljoyc.cqrs;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.messaging.Source;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableBinding(Source.class)
|
||||
public class SourceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.amaljoyc.cqrs.api;
|
||||
|
||||
import com.amaljoyc.cqrs.application.BankAccountService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 17.10.18.
|
||||
*/
|
||||
@RestController("/bankAccount")
|
||||
public class BankAccountController {
|
||||
|
||||
@Autowired
|
||||
private BankAccountService bankAccountService;
|
||||
|
||||
@PostMapping("/credit")
|
||||
ResponseEntity credit(@RequestBody CreditCommand creditCommand) {
|
||||
bankAccountService.creditAmount(creditCommand.getAccountNumber(), creditCommand.getAmount());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping("/debit")
|
||||
ResponseEntity debit(@RequestBody DebitCommand debitCommand) {
|
||||
bankAccountService.debitAmount(debitCommand.getAccountNumber(), debitCommand.getAmount());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.amaljoyc.cqrs.api;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 17.10.18.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreditCommand {
|
||||
private String accountNumber;
|
||||
private Long amount;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.amaljoyc.cqrs.api;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 17.10.18.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DebitCommand {
|
||||
private String accountNumber;
|
||||
private Long amount;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.amaljoyc.cqrs.application;
|
||||
|
||||
import com.amaljoyc.cqrs.event.AmountCredited;
|
||||
import com.amaljoyc.cqrs.event.AmountDebited;
|
||||
import com.amaljoyc.cqrs.event.DomainEventPublisher;
|
||||
import com.amaljoyc.cqrs.model.BankAccount;
|
||||
import com.amaljoyc.cqrs.persistence.BankAccountRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 17.10.18.
|
||||
*/
|
||||
@Service
|
||||
public class BankAccountService {
|
||||
|
||||
@Autowired
|
||||
private BankAccountRepository bankAccountRepository;
|
||||
|
||||
@Autowired
|
||||
private DomainEventPublisher domainEventPublisher;
|
||||
|
||||
@Transactional
|
||||
public void creditAmount(String accountNumber, Long amount) {
|
||||
BankAccount bankAccount = bankAccountRepository.findByAccountNumber(accountNumber)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid accountNumber :" + accountNumber));
|
||||
|
||||
bankAccount.credit(amount);
|
||||
domainEventPublisher.publish(new AmountCredited(accountNumber, amount));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void debitAmount(String accountNumber, Long amount) {
|
||||
BankAccount bankAccount = bankAccountRepository.findByAccountNumber(accountNumber)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid accountNumber :" + accountNumber));
|
||||
|
||||
bankAccount.debit(amount);
|
||||
domainEventPublisher.publish(new AmountDebited(accountNumber, amount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.amaljoyc.cqrs.event;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 18.10.18.
|
||||
*/
|
||||
public enum AccountProcessType {
|
||||
|
||||
CREDIT,
|
||||
DEBIT;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.amaljoyc.cqrs.event;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 18.10.18.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class AmountCredited implements DomainEvent {
|
||||
|
||||
private String accountNumber;
|
||||
private AccountProcessType type;
|
||||
private Long amount;
|
||||
private Instant timestamp;
|
||||
|
||||
public AmountCredited(String accountNumber, Long amount) {
|
||||
this.accountNumber = accountNumber;
|
||||
this.type = AccountProcessType.CREDIT;
|
||||
this.amount = amount;
|
||||
this.timestamp = Instant.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.amaljoyc.cqrs.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 18.10.18.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AmountDebited implements DomainEvent {
|
||||
|
||||
private String accountNumber;
|
||||
private AccountProcessType type;
|
||||
private Long amount;
|
||||
private Instant timestamp;
|
||||
|
||||
public AmountDebited(String accountNumber, Long amount) {
|
||||
this.accountNumber = accountNumber;
|
||||
this.type = AccountProcessType.DEBIT;
|
||||
this.amount = amount;
|
||||
this.timestamp = Instant.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.amaljoyc.cqrs.event;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 18.10.18.
|
||||
*/
|
||||
public interface DomainEvent {
|
||||
|
||||
String getType();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.amaljoyc.cqrs.event;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 18.10.18.
|
||||
*/
|
||||
public interface DomainEventPublisher {
|
||||
|
||||
void publish(DomainEvent event);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.amaljoyc.cqrs.event;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.stream.messaging.Source;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 18.10.18.
|
||||
*/
|
||||
@Component
|
||||
public class KafkaDomainEventPublisher implements DomainEventPublisher {
|
||||
|
||||
@Autowired
|
||||
private Source source;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public void publish(DomainEvent event) {
|
||||
try {
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
headers.put("type", event.getType());
|
||||
String content = objectMapper.writeValueAsString(event);
|
||||
|
||||
source.output().send(new GenericMessage<>(content, headers));
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.amaljoyc.cqrs.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 17.10.18.
|
||||
*/
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
public class BankAccount {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Getter
|
||||
private Long id;
|
||||
|
||||
private String accountNumber;
|
||||
private Long balance;
|
||||
|
||||
public void credit(Long amount) {
|
||||
balance += amount;
|
||||
}
|
||||
|
||||
public void debit(Long amount) {
|
||||
if (amount > balance) {
|
||||
throw new IllegalArgumentException("Not enough balance available for debit");
|
||||
}
|
||||
|
||||
balance -= amount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.amaljoyc.cqrs.persistence;
|
||||
|
||||
import com.amaljoyc.cqrs.model.BankAccount;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Created by amaljoyc on 17.10.18.
|
||||
*/
|
||||
public interface BankAccountRepository extends JpaRepository<BankAccount, Long> {
|
||||
|
||||
Optional<BankAccount> findByAccountNumber(String accountNumber);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user