Integration Test
This commit is contained in:
@ -122,7 +122,7 @@
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="13" language="java" name="com.iluwatar.event.sourcing.service.AccountService" project="event-sourcing"
|
||||
<class id="13" language="java" name="AccountService" project="event-sourcing"
|
||||
file="/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="687" y="68"/>
|
||||
@ -132,7 +132,7 @@
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="14" language="java" name="com.iluwatar.event.sourcing.service.MoneyTransactionService"
|
||||
<class id="14" language="java" name="MoneyTransactionService"
|
||||
project="event-sourcing"
|
||||
file="/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
|
@ -20,14 +20,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.event.sourcing.service;
|
||||
package com.iluwatar.event.sourcing;
|
||||
|
||||
import com.iluwatar.event.sourcing.api.EventProcessor;
|
||||
import com.iluwatar.event.sourcing.event.AccountCreateEvent;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class AccountService {
|
||||
|
@ -20,7 +20,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.event.sourcing.service;
|
||||
package com.iluwatar.event.sourcing;
|
||||
|
||||
import com.iluwatar.event.sourcing.api.EventProcessor;
|
||||
import com.iluwatar.event.sourcing.event.MoneyDepositEvent;
|
||||
@ -30,7 +30,7 @@ import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class MoneyTransactionService {
|
||||
|
@ -20,10 +20,10 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.event.sourcing.service;
|
||||
package com.iluwatar.event.sourcing;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class SequenceIdGenerator {
|
||||
|
@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.api;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public abstract class DomainEvent implements Serializable {
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
package com.iluwatar.event.sourcing.api;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public interface EventProcessor {
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
package com.iluwatar.event.sourcing.api;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public interface ProcessorJournal {
|
||||
|
||||
|
@ -24,62 +24,82 @@ package com.iluwatar.event.sourcing.app;
|
||||
|
||||
import com.iluwatar.event.sourcing.journal.JsonFileJournal;
|
||||
import com.iluwatar.event.sourcing.processor.DomainEventProcessor;
|
||||
import com.iluwatar.event.sourcing.service.AccountService;
|
||||
import com.iluwatar.event.sourcing.service.MoneyTransactionService;
|
||||
import com.iluwatar.event.sourcing.AccountService;
|
||||
import com.iluwatar.event.sourcing.MoneyTransactionService;
|
||||
import com.iluwatar.event.sourcing.state.AccountAggregate;
|
||||
import java.math.BigDecimal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Event Sourcing : Instead of storing just the current state of the data in a domain, use an
|
||||
* append-only store to record the full series of actions taken on that data. The store acts as the
|
||||
* system of record and can be used to materialize the domain objects. This can simplify tasks in
|
||||
* complex domains, by avoiding the need to synchronize the data model and the business domain,
|
||||
* while improving performance, scalability, and responsiveness. It can also provide consistency for
|
||||
* transactional data, and maintain full audit trails and history that can enable compensating
|
||||
* actions.
|
||||
*
|
||||
* This App class is an example usage of Event Sourcing pattern. As an example, two bank account is
|
||||
* created, then some money deposit and transfer actions are taken so a new state of accounts is
|
||||
* created. At that point, state is cleared in order to represent a system shot down. After the shot
|
||||
* down, system state is recovered by re-creating the past events from event journal. Then state is
|
||||
* printed so a user can view the last state is same with the state before system shot down.
|
||||
*
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
public static final int ACCOUNT_OF_DAENERYS = 1;
|
||||
public static final int ACCOUNT_OF_JON = 2;
|
||||
|
||||
/**
|
||||
* The entry point of application.
|
||||
*
|
||||
* @param args the input arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Running the system first time............");
|
||||
|
||||
DomainEventProcessor domainEventProcessor = new DomainEventProcessor();
|
||||
JsonFileJournal jsonFileJournal = new JsonFileJournal();
|
||||
jsonFileJournal.reset();
|
||||
domainEventProcessor.setPrecessorJournal(jsonFileJournal);
|
||||
|
||||
System.out.println("Creating th accounts............");
|
||||
|
||||
AccountService accountService = new AccountService(domainEventProcessor);
|
||||
MoneyTransactionService moneyTransactionService = new MoneyTransactionService(
|
||||
domainEventProcessor);
|
||||
accountService.createAccount(1, "Daenerys Targaryen");
|
||||
accountService.createAccount(2, "Jon Snow");
|
||||
|
||||
System.out.println("Do some money operations............");
|
||||
LOGGER.info("Running the system first time............");
|
||||
jsonFileJournal.reset();
|
||||
|
||||
moneyTransactionService.depositMoney(1, new BigDecimal("100000"));
|
||||
moneyTransactionService.depositMoney(2, new BigDecimal("100"));
|
||||
LOGGER.info("Creating th accounts............");
|
||||
|
||||
moneyTransactionService.transferMoney(1, 2, new BigDecimal("10000"));
|
||||
moneyTransactionService.withdrawalMoney(2, new BigDecimal("1000"));
|
||||
accountService.createAccount(ACCOUNT_OF_DAENERYS, "Daenerys Targaryen");
|
||||
accountService.createAccount(ACCOUNT_OF_JON, "Jon Snow");
|
||||
|
||||
System.out.println("...............State:............");
|
||||
System.out.println(AccountAggregate.getAccount(1));
|
||||
System.out.println(AccountAggregate.getAccount(2));
|
||||
LOGGER.info("Do some money operations............");
|
||||
|
||||
System.out.println("At that point system goes down state in memory cleared............");
|
||||
moneyTransactionService.depositMoney(ACCOUNT_OF_DAENERYS, new BigDecimal("100000"));
|
||||
moneyTransactionService.depositMoney(ACCOUNT_OF_JON, new BigDecimal("100"));
|
||||
|
||||
moneyTransactionService.transferMoney(ACCOUNT_OF_DAENERYS, ACCOUNT_OF_JON, new BigDecimal("10000"));
|
||||
moneyTransactionService.withdrawalMoney(ACCOUNT_OF_JON, new BigDecimal("1000"));
|
||||
|
||||
LOGGER.info("...............State:............");
|
||||
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString());
|
||||
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString());
|
||||
|
||||
LOGGER.info("At that point system had a shot down, state in memory is cleared............");
|
||||
AccountAggregate.resetState();
|
||||
|
||||
System.out.println("Recover the syste by the events in journal file............");
|
||||
LOGGER.info("Recover the system by the events in journal file............");
|
||||
|
||||
domainEventProcessor = new DomainEventProcessor();
|
||||
jsonFileJournal = new JsonFileJournal();
|
||||
domainEventProcessor.setPrecessorJournal(jsonFileJournal);
|
||||
domainEventProcessor.recover();
|
||||
|
||||
System.out.println("...............State Recovered:............");
|
||||
System.out.println(AccountAggregate.getAccount(1));
|
||||
System.out.println(AccountAggregate.getAccount(2));
|
||||
LOGGER.info("...............Recovered State:............");
|
||||
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString());
|
||||
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString());
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class Account {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.domain;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class Transaction {
|
||||
|
||||
|
@ -27,7 +27,7 @@ import com.iluwatar.event.sourcing.domain.Account;
|
||||
import com.iluwatar.event.sourcing.state.AccountAggregate;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class AccountCreateEvent extends DomainEvent {
|
||||
|
||||
|
@ -28,7 +28,7 @@ import com.iluwatar.event.sourcing.state.AccountAggregate;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class MoneyDepositEvent extends DomainEvent {
|
||||
|
||||
|
@ -28,7 +28,7 @@ import com.iluwatar.event.sourcing.state.AccountAggregate;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class MoneyTransferEvent extends DomainEvent {
|
||||
|
||||
|
@ -28,7 +28,7 @@ import com.iluwatar.event.sourcing.state.AccountAggregate;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class MoneyWithdrawalEvent extends DomainEvent {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.gateway;
|
||||
import com.iluwatar.event.sourcing.domain.Account;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class AccountCreateContractSender {
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
package com.iluwatar.event.sourcing.gateway;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class Gateways {
|
||||
|
||||
|
@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.gateway;
|
||||
import com.iluwatar.event.sourcing.domain.Transaction;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class TransactionLogger {
|
||||
|
||||
|
@ -44,7 +44,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class JsonFileJournal implements ProcessorJournal {
|
||||
|
||||
|
@ -27,7 +27,7 @@ import com.iluwatar.event.sourcing.api.EventProcessor;
|
||||
import com.iluwatar.event.sourcing.api.ProcessorJournal;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class DomainEventProcessor implements EventProcessor {
|
||||
|
||||
|
@ -27,7 +27,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by serdarh on 06.08.2017.
|
||||
* Created by Serdar Hamzaogullari on 06.08.2017.
|
||||
*/
|
||||
public class AccountAggregate {
|
||||
|
||||
|
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 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.event.sourcing;
|
||||
|
||||
import static com.iluwatar.event.sourcing.app.App.ACCOUNT_OF_DAENERYS;
|
||||
import static com.iluwatar.event.sourcing.app.App.ACCOUNT_OF_JON;
|
||||
|
||||
import com.iluwatar.event.sourcing.domain.Account;
|
||||
import com.iluwatar.event.sourcing.journal.JsonFileJournal;
|
||||
import com.iluwatar.event.sourcing.processor.DomainEventProcessor;
|
||||
import com.iluwatar.event.sourcing.state.AccountAggregate;
|
||||
import java.math.BigDecimal;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Intergartion Test for Event Sourcing state recovery
|
||||
*
|
||||
* Created by Serdar Hamzaogullari on 19.08.2017.
|
||||
*/
|
||||
public class IntegrationTest {
|
||||
|
||||
/**
|
||||
* The Domain event processor.
|
||||
*/
|
||||
DomainEventProcessor domainEventProcessor;
|
||||
/**
|
||||
* The Json file journal.
|
||||
*/
|
||||
JsonFileJournal jsonFileJournal;
|
||||
/**
|
||||
* The Account service.
|
||||
*/
|
||||
AccountService accountService;
|
||||
/**
|
||||
* The Money transaction service.
|
||||
*/
|
||||
MoneyTransactionService moneyTransactionService;
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
@Before
|
||||
public void initialize() {
|
||||
domainEventProcessor = new DomainEventProcessor();
|
||||
jsonFileJournal = new JsonFileJournal();
|
||||
domainEventProcessor.setPrecessorJournal(jsonFileJournal);
|
||||
accountService = new AccountService(domainEventProcessor);
|
||||
moneyTransactionService = new MoneyTransactionService(
|
||||
domainEventProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test state recovery.
|
||||
*/
|
||||
@Test
|
||||
public void testStateRecovery() {
|
||||
jsonFileJournal.reset();
|
||||
|
||||
accountService.createAccount(ACCOUNT_OF_DAENERYS, "Daenerys Targaryen");
|
||||
accountService.createAccount(ACCOUNT_OF_JON, "Jon Snow");
|
||||
|
||||
moneyTransactionService.depositMoney(ACCOUNT_OF_DAENERYS, new BigDecimal("100000"));
|
||||
moneyTransactionService.depositMoney(ACCOUNT_OF_JON, new BigDecimal("100"));
|
||||
|
||||
moneyTransactionService
|
||||
.transferMoney(ACCOUNT_OF_DAENERYS, ACCOUNT_OF_JON, new BigDecimal("10000"));
|
||||
moneyTransactionService.withdrawalMoney(ACCOUNT_OF_JON, new BigDecimal("1000"));
|
||||
|
||||
Account accountOfDaenerysBeforeShotDown = AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS);
|
||||
Account accountOfJonBeforeShotDown = AccountAggregate.getAccount(ACCOUNT_OF_JON);
|
||||
|
||||
AccountAggregate.resetState();
|
||||
|
||||
domainEventProcessor = new DomainEventProcessor();
|
||||
jsonFileJournal = new JsonFileJournal();
|
||||
domainEventProcessor.setPrecessorJournal(jsonFileJournal);
|
||||
domainEventProcessor.recover();
|
||||
|
||||
Account accountOfDaenerysAfterShotDown = AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS);
|
||||
Account accountOfJonAfterShotDown = AccountAggregate.getAccount(ACCOUNT_OF_JON);
|
||||
|
||||
Assert.assertEquals(accountOfDaenerysBeforeShotDown.getMoney(),
|
||||
accountOfDaenerysAfterShotDown.getMoney());
|
||||
Assert
|
||||
.assertEquals(accountOfJonBeforeShotDown.getMoney(), accountOfJonAfterShotDown.getMoney());
|
||||
Assert.assertEquals(accountOfDaenerysBeforeShotDown.getTransactions().size(),
|
||||
accountOfDaenerysAfterShotDown.getTransactions().size());
|
||||
Assert.assertEquals(accountOfJonBeforeShotDown.getTransactions().size(),
|
||||
accountOfJonAfterShotDown.getTransactions().size());
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user