diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml
index 6dc90063e..35d462cb1 100644
--- a/event-sourcing/pom.xml
+++ b/event-sourcing/pom.xml
@@ -39,5 +39,12 @@
junit
test
+
+
+ com.google.code.gson
+ gson
+ 2.8.1
+
+
\ No newline at end of file
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java
new file mode 100644
index 000000000..d77654869
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java
@@ -0,0 +1,41 @@
+package com.iluwatar.event.sourcing.api;
+
+import java.io.Serializable;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public abstract class DomainEvent implements Serializable {
+ private final long sequenceId;
+ private final long createdTime;
+ private boolean replica = false;
+ private final String eventClassName;
+
+ public DomainEvent(long sequenceId, long createdTime, String eventClassName) {
+ this.sequenceId = sequenceId;
+ this.createdTime = createdTime;
+ this.eventClassName = eventClassName;
+ }
+
+ public long getSequenceId() {
+ return sequenceId;
+ }
+
+ public long getCreatedTime() {
+ return createdTime;
+ }
+
+ public boolean isReplica() {
+ return replica;
+ }
+
+ public void setReplica(boolean replica) {
+ this.replica = replica;
+ }
+
+ public abstract void process();
+
+ public String getEventClassName() {
+ return eventClassName;
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java
new file mode 100644
index 000000000..729efc83c
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java
@@ -0,0 +1,11 @@
+package com.iluwatar.event.sourcing.api;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public interface EventProcessor {
+ void process(DomainEvent domainEvent);
+ void setPrecessorJournal(ProcessorJournal precessorJournal);
+ void addExternalEventListener(ExternalEventListener externalEventListener);
+ void recover();
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java
new file mode 100644
index 000000000..a1cb78108
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java
@@ -0,0 +1,8 @@
+package com.iluwatar.event.sourcing.api;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public interface ExternalEventListener {
+ void notify(DomainEvent domainEvent);
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java
new file mode 100644
index 000000000..906c66247
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java
@@ -0,0 +1,10 @@
+package com.iluwatar.event.sourcing.api;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public interface ProcessorJournal {
+ void write(DomainEvent domainEvent);
+ void reset();
+ DomainEvent readNext();
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java
new file mode 100644
index 000000000..8627736f1
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java
@@ -0,0 +1,58 @@
+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.state.AccountAggregate;
+
+import java.math.BigDecimal;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class App {
+
+ 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............");
+
+ moneyTransactionService.depositMoney(1,new BigDecimal("100000"));
+ moneyTransactionService.depositMoney(2,new BigDecimal("10"));
+
+ moneyTransactionService.transferMoney(1,2,new BigDecimal("10000"));
+ moneyTransactionService.withdrawalMoney(2, new BigDecimal("1000"));
+
+ System.out.println("...............State:............");
+ System.out.println(AccountAggregate.getAccount(1));
+ System.out.println(AccountAggregate.getAccount(2));
+
+ System.out.println("At that point system goes down state in memory cleared............");
+
+ AccountAggregate.resetState();
+
+ System.out.println("Recover the syste 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));
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java
new file mode 100644
index 000000000..5a7a77fcf
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java
@@ -0,0 +1,63 @@
+package com.iluwatar.event.sourcing.domain;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class Account {
+ private final int accountNo;
+ private final String owner;
+ private BigDecimal money;
+ private List transactions;
+
+ public Account(int accountNo, String owner) {
+ this.accountNo = accountNo;
+ this.owner = owner;
+ money = BigDecimal.ZERO;
+ transactions = new ArrayList<>();
+ }
+
+ public int getAccountNo() {
+ return accountNo;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public BigDecimal getMoney() {
+ return money;
+ }
+
+ public List getTransactions() {
+ return transactions;
+ }
+
+ public void setMoney(BigDecimal money) {
+ this.money = money;
+ }
+
+ public void setTransactions(List transactions) {
+ this.transactions = transactions;
+ }
+
+ public Account copy() {
+ Account account = new Account(accountNo, owner);
+ account.setMoney(money);
+ account.setTransactions(transactions);
+ return account;
+ }
+
+ @Override
+ public String toString() {
+ return "Account{" +
+ "accountNo=" + accountNo +
+ ", owner='" + owner + '\'' +
+ ", money=" + money +
+ ", transactions=" + transactions +
+ '}';
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java
new file mode 100644
index 000000000..557efbedc
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java
@@ -0,0 +1,46 @@
+package com.iluwatar.event.sourcing.domain;
+
+import java.math.BigDecimal;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class Transaction {
+ private final int accountNo;
+ private final BigDecimal moneyIn;
+ private final BigDecimal moneyOut;
+ private final BigDecimal lastBalance;
+
+ public Transaction(int accountNo, BigDecimal moneyIn, BigDecimal moneyOut, BigDecimal lastBalance) {
+ this.accountNo = accountNo;
+ this.moneyIn = moneyIn;
+ this.moneyOut = moneyOut;
+ this.lastBalance = lastBalance;
+ }
+
+ public int getAccountNo() {
+ return accountNo;
+ }
+
+ public BigDecimal getMoneyIn() {
+ return moneyIn;
+ }
+
+ public BigDecimal getMoneyOut() {
+ return moneyOut;
+ }
+
+ public BigDecimal getLastBalance() {
+ return lastBalance;
+ }
+
+ @Override
+ public String toString() {
+ return "Transaction{" +
+ "accountNo=" + accountNo +
+ ", moneyIn=" + moneyIn +
+ ", moneyOut=" + moneyOut +
+ ", lastBalance=" + lastBalance +
+ '}';
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java
new file mode 100644
index 000000000..3957a4fe7
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java
@@ -0,0 +1,43 @@
+package com.iluwatar.event.sourcing.event;
+
+import com.iluwatar.event.sourcing.api.DomainEvent;
+import com.iluwatar.event.sourcing.domain.Account;
+import com.iluwatar.event.sourcing.gateway.Gateways;
+import com.iluwatar.event.sourcing.state.AccountAggregate;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class AccountCreateEvent extends DomainEvent {
+ private final int accountNo;
+ private final String owner;
+
+ public AccountCreateEvent(long sequenceId, long createdTime, int accountNo, String owner) {
+ super(sequenceId, createdTime, "AccountCreateEvent");
+ this.accountNo = accountNo;
+ this.owner = owner;
+ }
+
+ public int getAccountNo() {
+ return accountNo;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ @Override
+ public void process() {
+ Account account = AccountAggregate.getAccount(accountNo);
+ if(account!=null){
+ throw new RuntimeException("Account already exists");
+ }
+ account = new Account(accountNo,owner);
+ AccountAggregate.putAccount(account);
+
+ // check if this event is replicated from journal before calling an external gateway function
+ if(!isReplica()) {
+ Gateways.getAccountCreateContractSender().sendContractInfo(account);
+ }
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java
new file mode 100644
index 000000000..ffa9d0763
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java
@@ -0,0 +1,38 @@
+package com.iluwatar.event.sourcing.event;
+
+import com.iluwatar.event.sourcing.api.DomainEvent;
+import com.iluwatar.event.sourcing.domain.Account;
+import com.iluwatar.event.sourcing.domain.Transaction;
+import com.iluwatar.event.sourcing.gateway.Gateways;
+import com.iluwatar.event.sourcing.state.AccountAggregate;
+
+import java.math.BigDecimal;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class MoneyDepositEvent extends DomainEvent {
+ private BigDecimal money;
+ private int accountNo;
+
+ public MoneyDepositEvent(long sequenceId, long createdTime, int accountNo,BigDecimal money) {
+ super(sequenceId, createdTime, "MoneyDepositEvent");
+ this.money = money;
+ this.accountNo = accountNo;
+ }
+
+ @Override
+ public void process() {
+ Account account = AccountAggregate.getAccount(accountNo);
+ if(account==null){
+ throw new RuntimeException("Account not found");
+ }
+ account.setMoney(account.getMoney().add(money));
+ Transaction transaction = new Transaction(accountNo,money,BigDecimal.ZERO,account.getMoney());
+ account.getTransactions().add(transaction);
+ AccountAggregate.putAccount(account);
+ if(!isReplica()) {
+ Gateways.getTransactionLogger().log(transaction);
+ }
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java
new file mode 100644
index 000000000..4e0fb9829
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java
@@ -0,0 +1,56 @@
+package com.iluwatar.event.sourcing.event;
+
+import com.iluwatar.event.sourcing.api.DomainEvent;
+import com.iluwatar.event.sourcing.domain.Account;
+import com.iluwatar.event.sourcing.domain.Transaction;
+import com.iluwatar.event.sourcing.gateway.Gateways;
+import com.iluwatar.event.sourcing.state.AccountAggregate;
+
+import java.math.BigDecimal;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class MoneyTransferEvent extends DomainEvent {
+ private BigDecimal money;
+ private int accountNoFrom;
+ private int accountNoTo;
+
+ public MoneyTransferEvent(long sequenceId, long createdTime, BigDecimal money, int accountNoFrom, int accountNoTo) {
+ super(sequenceId, createdTime, "MoneyTransferEvent");
+ this.money = money;
+ this.accountNoFrom = accountNoFrom;
+ this.accountNoTo = accountNoTo;
+ }
+
+ @Override
+ public void process() {
+ Account accountFrom = AccountAggregate.getAccount(accountNoFrom);
+ if(accountFrom==null){
+ throw new RuntimeException("Account not found "+accountNoFrom);
+ }
+ Account accountTo = AccountAggregate.getAccount(accountNoTo);
+ if(accountTo==null){
+ throw new RuntimeException("Account not found"+ accountTo);
+ }
+ if(accountFrom.getMoney().compareTo(money)==-1){
+ throw new RuntimeException("Insufficient Account Balance");
+ }
+ accountFrom.setMoney(accountFrom.getMoney().subtract(money));
+ accountTo.setMoney(accountTo.getMoney().add(money));
+
+ Transaction transactionFrom = new Transaction(accountNoFrom,BigDecimal.ZERO,money,accountFrom.getMoney());
+ accountFrom.getTransactions().add(transactionFrom);
+
+ Transaction transactionTo = new Transaction(accountNoTo,money,BigDecimal.ZERO,accountTo.getMoney());
+ accountTo.getTransactions().add(transactionTo);
+
+ AccountAggregate.putAccount(accountFrom);
+ AccountAggregate.putAccount(accountTo);
+
+ if(!isReplica()) {
+ Gateways.getTransactionLogger().log(transactionFrom);
+ Gateways.getTransactionLogger().log(transactionTo);
+ }
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java
new file mode 100644
index 000000000..27a63d13d
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java
@@ -0,0 +1,38 @@
+package com.iluwatar.event.sourcing.event;
+
+import com.iluwatar.event.sourcing.api.DomainEvent;
+import com.iluwatar.event.sourcing.domain.Account;
+import com.iluwatar.event.sourcing.domain.Transaction;
+import com.iluwatar.event.sourcing.gateway.Gateways;
+import com.iluwatar.event.sourcing.state.AccountAggregate;
+
+import java.math.BigDecimal;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class MoneyWithdrawalEvent extends DomainEvent {
+ private BigDecimal money;
+ private int accountNo;
+
+ public MoneyWithdrawalEvent(long sequenceId, long createdTime, int accountNo,BigDecimal money) {
+ super(sequenceId, createdTime, "MoneyWithdrawalEvent");
+ this.money = money;
+ this.accountNo = accountNo;
+ }
+
+ @Override
+ public void process() {
+ Account account = AccountAggregate.getAccount(accountNo);
+ if(account==null){
+ throw new RuntimeException("Account not found");
+ }
+ account.setMoney(account.getMoney().subtract(money));
+ Transaction transaction = new Transaction(accountNo,BigDecimal.ZERO,money,account.getMoney());
+ account.getTransactions().add(transaction);
+ AccountAggregate.putAccount(account);
+ if(!isReplica()) {
+ Gateways.getTransactionLogger().log(transaction);
+ }
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java
new file mode 100644
index 000000000..42dfccf7b
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java
@@ -0,0 +1,12 @@
+package com.iluwatar.event.sourcing.gateway;
+
+import com.iluwatar.event.sourcing.domain.Account;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class AccountCreateContractSender {
+ public void sendContractInfo(Account account){
+ // an example imaginary funciton which sends account info to some external end point
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java
new file mode 100644
index 000000000..d167393bf
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java
@@ -0,0 +1,17 @@
+package com.iluwatar.event.sourcing.gateway;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class Gateways {
+ private static AccountCreateContractSender accountCreateContractSender = new AccountCreateContractSender();
+ private static TransactionLogger transactionLogger = new TransactionLogger();
+
+ public static AccountCreateContractSender getAccountCreateContractSender() {
+ return accountCreateContractSender;
+ }
+
+ public static TransactionLogger getTransactionLogger() {
+ return transactionLogger;
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java
new file mode 100644
index 000000000..6d961d96e
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java
@@ -0,0 +1,12 @@
+package com.iluwatar.event.sourcing.gateway;
+
+import com.iluwatar.event.sourcing.domain.Transaction;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class TransactionLogger {
+ public void log(Transaction transaction) {
+ // example imaginary function that logs the transaction to somewhere
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java
new file mode 100644
index 000000000..45a982c19
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java
@@ -0,0 +1,99 @@
+package com.iluwatar.event.sourcing.journal;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.iluwatar.event.sourcing.api.DomainEvent;
+import com.iluwatar.event.sourcing.api.ProcessorJournal;
+import com.iluwatar.event.sourcing.event.AccountCreateEvent;
+import com.iluwatar.event.sourcing.event.MoneyDepositEvent;
+import com.iluwatar.event.sourcing.event.MoneyTransferEvent;
+import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class JsonFileJournal implements ProcessorJournal{
+
+ private File aFile;
+ private List events = new ArrayList<>();
+ private int index = 0;
+ public JsonFileJournal() {
+ aFile = new File("Journal.json");
+ if(aFile.exists()) {
+ try (BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(aFile), "UTF-8"))) {
+ String line;
+ while ((line = input.readLine()) != null) {
+ events.add(line);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }else{
+ reset();
+ }
+ }
+
+ @Override
+ public void write(DomainEvent domainEvent) {
+ Gson gson = new Gson();
+ JsonElement jsonElement;
+ if(domainEvent instanceof AccountCreateEvent) {
+ jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class);
+ }else if(domainEvent instanceof MoneyDepositEvent) {
+ jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class);
+ }else if(domainEvent instanceof MoneyWithdrawalEvent) {
+ jsonElement = gson.toJsonTree(domainEvent, MoneyWithdrawalEvent.class);
+ }else if(domainEvent instanceof MoneyTransferEvent) {
+ jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class);
+ }else{
+ throw new RuntimeException("Journal Event not recegnized");
+ }
+
+ try (Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aFile, true), "UTF-8"))) {
+ String eventString = jsonElement.toString();
+ output.write(eventString +"\r\n");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void reset() {
+ aFile.delete();
+ }
+
+
+ @Override
+ public DomainEvent readNext() {
+ if(index>=events.size()){
+ return null;
+ }
+ String event = events.get(index);
+ index++;
+
+ JsonParser parser = new JsonParser();
+ JsonElement jsonElement = parser.parse(event);
+ String eventClassName = jsonElement.getAsJsonObject().get("eventClassName").getAsString();
+ Gson gson = new Gson();
+ DomainEvent domainEvent;
+ if(eventClassName.equals("AccountCreateEvent")) {
+ domainEvent = gson.fromJson(jsonElement, AccountCreateEvent.class);
+ }else if(eventClassName.equals("MoneyDepositEvent")) {
+ domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class);
+ }else if(eventClassName.equals("MoneyTransferEvent")) {
+ domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class);
+ }else if(eventClassName.equals("MoneyWithdrawalEvent")) {
+ domainEvent = gson.fromJson(jsonElement, MoneyWithdrawalEvent.class);
+ }else{
+ throw new RuntimeException("Journal Event not recegnized");
+ }
+
+ domainEvent.setReplica(true);
+ return domainEvent;
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java
new file mode 100644
index 000000000..a23c41905
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java
@@ -0,0 +1,48 @@
+package com.iluwatar.event.sourcing.processor;
+
+import com.iluwatar.event.sourcing.api.DomainEvent;
+import com.iluwatar.event.sourcing.api.EventProcessor;
+import com.iluwatar.event.sourcing.api.ExternalEventListener;
+import com.iluwatar.event.sourcing.api.ProcessorJournal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class DomainEventProcessor implements EventProcessor {
+
+ private ProcessorJournal precessorJournal;
+ private List externalEventListeners = new ArrayList<>();
+
+ @Override
+ public void process(DomainEvent domainEvent) {
+ externalEventListeners.forEach(externalEventListener -> externalEventListener.notify(domainEvent));
+ domainEvent.process();
+ precessorJournal.write(domainEvent);
+ }
+
+ @Override
+ public void setPrecessorJournal(ProcessorJournal precessorJournal) {
+ this.precessorJournal = precessorJournal;
+ }
+
+ @Override
+ public void addExternalEventListener(ExternalEventListener externalEventListener) {
+ externalEventListeners.add(externalEventListener);
+ }
+
+ @Override
+ public void recover() {
+ DomainEvent domainEvent;
+ while(true) {
+ domainEvent = precessorJournal.readNext();
+ if(domainEvent==null){
+ break;
+ }else{
+ domainEvent.process();
+ }
+ }
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java
new file mode 100644
index 000000000..b0a707788
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java
@@ -0,0 +1,22 @@
+package com.iluwatar.event.sourcing.service;
+
+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.
+ */
+public class AccountService {
+ private EventProcessor eventProcessor;
+
+ public AccountService(EventProcessor eventProcessor) {
+ this.eventProcessor = eventProcessor;
+ }
+
+ public void createAccount(int accountNo, String owner){
+ AccountCreateEvent accountCreateEvent = new AccountCreateEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(),accountNo,owner);
+ eventProcessor.process(accountCreateEvent);
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java
new file mode 100644
index 000000000..80c2a5a4f
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java
@@ -0,0 +1,35 @@
+package com.iluwatar.event.sourcing.service;
+
+import com.iluwatar.event.sourcing.api.EventProcessor;
+import com.iluwatar.event.sourcing.event.MoneyDepositEvent;
+import com.iluwatar.event.sourcing.event.MoneyTransferEvent;
+import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class MoneyTransactionService {
+ private EventProcessor eventProcessor;
+
+ public MoneyTransactionService(EventProcessor eventProcessor) {
+ this.eventProcessor = eventProcessor;
+ }
+
+ public void depositMoney(int accountNo, BigDecimal money){
+ MoneyDepositEvent moneyDepositEvent = new MoneyDepositEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money);
+ eventProcessor.process(moneyDepositEvent);
+ }
+
+ public void withdrawalMoney(int accountNo, BigDecimal money){
+ MoneyWithdrawalEvent moneyWithdrawalEvent = new MoneyWithdrawalEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money);
+ eventProcessor.process(moneyWithdrawalEvent);
+ }
+
+ public void transferMoney(int accountNoFrom, int accountNoTo, BigDecimal money){
+ MoneyTransferEvent moneyTransferEvent = new MoneyTransferEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), money, accountNoFrom, accountNoTo);
+ eventProcessor.process(moneyTransferEvent);
+ }
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java
new file mode 100644
index 000000000..2eec6a70d
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java
@@ -0,0 +1,14 @@
+package com.iluwatar.event.sourcing.service;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class SequenceIdGenerator {
+ private static long sequenceId = 0L;
+
+ public static long nextSequenceId(){
+ sequenceId++;
+ return sequenceId;
+ }
+
+}
diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java
new file mode 100644
index 000000000..b927af0e1
--- /dev/null
+++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java
@@ -0,0 +1,29 @@
+package com.iluwatar.event.sourcing.state;
+
+import com.iluwatar.event.sourcing.domain.Account;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by serdarh on 06.08.2017.
+ */
+public class AccountAggregate {
+ private static Map accounts = new HashMap<>();
+
+ public static void putAccount(Account account){
+ accounts.put(account.getAccountNo(), account);
+ }
+
+ public static Account getAccount(int accountNo){
+ Account account = accounts.get(accountNo);
+ if(account == null){
+ return null;
+ }
+ return account.copy();
+ }
+
+ public static void resetState(){
+ accounts = new HashMap<>();
+ }
+}
diff --git a/pom.xml b/pom.xml
index 4f4b5dee6..5f46c9401 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,6 +143,7 @@
extension-objects
marker
cqrs
+ event-sourcing