Compare commits
59 Commits
wip-eventu
...
wip-eventu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ae6db7229 | ||
|
|
c03a5fed8d | ||
|
|
ee45163f2c | ||
|
|
e6bf638b4b | ||
|
|
d6f60101db | ||
|
|
e54577d656 | ||
|
|
bae00f6bd7 | ||
|
|
68dca23a6b | ||
|
|
19c9f88a7f | ||
|
|
9b6956b8df | ||
|
|
e2de325df2 | ||
|
|
c9fa916cdd | ||
|
|
f79ebb4d18 | ||
|
|
8f2fc83a34 | ||
|
|
05f2f309e7 | ||
|
|
6cf774da2a | ||
|
|
3c2e9d374c | ||
|
|
55cb34ef4f | ||
|
|
dde554e442 | ||
|
|
fd75779093 | ||
|
|
c8291bec71 | ||
|
|
1005c47d83 | ||
|
|
47e9053285 | ||
|
|
f76912a6cf | ||
|
|
625ea6007e | ||
|
|
6fae59fdeb | ||
|
|
f846a32d95 | ||
|
|
2a712017f1 | ||
|
|
85613936f4 | ||
|
|
6f480ad11a | ||
|
|
2b0c405378 | ||
|
|
a5d1e7312c | ||
|
|
1b53bd9147 | ||
|
|
d1328e4ce8 | ||
|
|
45bda8e14d | ||
|
|
d9e13ff669 | ||
|
|
e14787bce8 | ||
|
|
1d14ece9cf | ||
|
|
1e13d482a8 | ||
|
|
2467099c3e | ||
|
|
f4ec33d275 | ||
|
|
a91ade08b1 | ||
|
|
fb97767a06 | ||
|
|
1e7234166a | ||
|
|
ef444bde9b | ||
|
|
4b73b9beed | ||
|
|
d0bdd51406 | ||
|
|
b0b32d0a3f | ||
|
|
e9517fe30f | ||
|
|
5f8475d675 | ||
|
|
12e46582cd | ||
|
|
b0855ebd81 | ||
|
|
39309f23a1 | ||
|
|
e488df3d06 | ||
|
|
4f11433390 | ||
|
|
b573027fc2 | ||
|
|
3117f12402 | ||
|
|
5b029d8307 | ||
|
|
6d8376cfd5 |
18
README.md
18
README.md
@@ -1,7 +1,7 @@
|
||||
#Event-Sourcing+CQRS example application
|
||||
|
||||
This example application is the money transfer application described in my talk [Building and deploying microservices with event sourcing, CQRS and Docker](http://plainoldobjects.com/presentations/building-and-deploying-microservices-with-event-sourcing-cqrs-and-docker/).
|
||||
This talk describe a way of architecting highly scalable and available applications that is based on microservices, polyglot persistence,
|
||||
This talk describes a way of architecting highly scalable and available applications that is based on microservices, polyglot persistence,
|
||||
event sourcing (ES) and command query responsibility segregation (CQRS).
|
||||
Applications consist of loosely coupled components that communicate using events.
|
||||
These components can be deployed either as separate services or packaged as a monolithic application for simplified development and testing.
|
||||
@@ -94,9 +94,12 @@ First, you need to tell the query side code how to connect to MongoDB:
|
||||
```
|
||||
|
||||
[Docker Compose](https://docs.docker.com/compose/) is a great way to run MongoDB.
|
||||
You can run the `docker-compose up -d mongodb` to run MongoDB.
|
||||
You can run the `docker-compose up -d mongodb` to run MongoDB and then set `SPRING_DATA_MONGODB_URI` as follows:
|
||||
```
|
||||
export SPRING_DATA_MONGODB_URI=mongodb://$(docker-machine ip default)/yourdb
|
||||
```
|
||||
|
||||
Second, some of the tests in accounts-command-side-service, transactions-command-side-service, accounts-query-side-service and e2e-test need you need to set some environment variables that tell them how to connect to the Event Store server.
|
||||
Second, some of the tests in accounts-command-side-service, transactions-command-side-service, accounts-query-side-service and e2e-test require you to set some environment variables that tell them how to connect to the Event Store server.
|
||||
But don't worry.
|
||||
The build is configured to ignore failures for those projects.
|
||||
|
||||
@@ -117,6 +120,15 @@ Simply use this command:
|
||||
java -jar monolithic-service/build/libs/monolithic-service.jar
|
||||
```
|
||||
|
||||
This will start the service running on port 8080 (you can change using the --server.port=9999 option).
|
||||
|
||||
Once the service has started you can open the Swagger UI: http://localhost:8080/swagger-ui.html.
|
||||
You can then:
|
||||
|
||||
1. Create two accounts (save the account ids)
|
||||
2. Create a money transfer
|
||||
3. View the updated account balances
|
||||
|
||||
## Running the microservices
|
||||
|
||||
The other option is to run the services separately.
|
||||
|
||||
@@ -7,19 +7,19 @@ This application consists of three microservices:
|
||||
* Account Service - the command side business logic for Accounts
|
||||
* Money Transfer Service - the command side business logic for Money Transfers
|
||||
* Query service - query side implementation of a MongoDB-based, denormalized view of Accounts and MoneyTransfers
|
||||
|
||||
|
||||
The Account Service consists of the following modules:
|
||||
|
||||
* accounts-command-side-backend - the Account aggregate
|
||||
* accounts-command-side-web - a REST API for creating and retrieving Accounts
|
||||
* accounts-command-side-service - a standalone microservice
|
||||
|
||||
|
||||
The Money Transfer Service consists of the following modules:
|
||||
|
||||
* transactions-command-side-backend - the MoneyTransfer aggregate
|
||||
* transactions-command-side-web - a REST API for creating and retrieving Money Transfers
|
||||
* transactions-command-side-service - a standalone microservice
|
||||
|
||||
|
||||
The Query Service consists the following modules:
|
||||
|
||||
* accounts-query-side-backend - MongoDB-based, denormalized view of Accounts and MoneyTransfers
|
||||
@@ -28,10 +28,8 @@ The Query Service consists the following modules:
|
||||
|
||||
# Deploying the application
|
||||
|
||||
These services can be deployed either as either separate standalone services using the Event Store server, or they can be deployed as a monolithic application for simpified integration testing.
|
||||
These services can be deployed either as either separate standalone services using the Event Store server, or they can be deployed as a monolithic application for simplified integration testing.
|
||||
|
||||
The three services can also be packaged as a single monolithic web application in order to be used with the embedded Event Store:
|
||||
|
||||
* monolithic-service - all-in-one, monolithic packaging of the application
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transa
|
||||
import java.math.BigDecimal;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@EventSubscriber(id="accountEventHandlers")
|
||||
public class AccountWorkflow {
|
||||
@EventSubscriber(id = "accountEventHandlers")
|
||||
public class AccountWorkflow {
|
||||
|
||||
@EventHandlerMethod
|
||||
public CompletableFuture<?> debitAccount(EventHandlerContext<MoneyTransferCreatedEvent> ctx) {
|
||||
@@ -22,7 +22,13 @@ public class AccountWorkflow {
|
||||
|
||||
String fromAccountId = event.getDetails().getFromAccountId();
|
||||
|
||||
return ctx.update(Account.class, fromAccountId, new DebitAccountCommand(amount, transactionId));
|
||||
return ctx.update(Account.class, fromAccountId, new DebitAccountCommand(amount, transactionId)).handle((x, e) -> {
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
@@ -32,7 +38,13 @@ public class AccountWorkflow {
|
||||
String fromAccountId = event.getDetails().getToAccountId();
|
||||
String transactionId = ctx.getEntityId();
|
||||
|
||||
return ctx.update(Account.class, fromAccountId, new CreditAccountCommand(amount, transactionId));
|
||||
return ctx.update(Account.class, fromAccountId, new CreditAccountCommand(amount, transactionId)).handle((x, e) -> {
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountRequest;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountResponse;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountRequest;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -25,7 +25,7 @@ public class AccountsCommandSideServiceIntegrationTest {
|
||||
private int port;
|
||||
|
||||
private String baseUrl(String path) {
|
||||
return "http://localhost:" + port + "/" + path;
|
||||
return "http://localhost:" + port + "/api" + path;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountRequest;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -11,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/accounts")
|
||||
@RequestMapping("/api/accounts")
|
||||
public class AccountController {
|
||||
|
||||
private AccountService accountService;
|
||||
|
||||
@@ -35,7 +35,7 @@ public class AccountControllerIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccount() throws Exception {
|
||||
mockMvc.perform(post("/accounts")
|
||||
mockMvc.perform(post("/api/accounts")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"customerId\" : \"00000000-00000000\", \"initialBalance\" : 500}")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
@@ -44,7 +44,7 @@ public class AccountControllerIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void shouldRejectBadRequest() throws Exception {
|
||||
mockMvc.perform(post("/accounts")
|
||||
mockMvc.perform(post("/api/accounts")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"initialBalanceXXX\" : 500}")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
public class AccountChangeInfo {
|
||||
|
||||
private String changeId;
|
||||
private String transactionId;
|
||||
private String transactionType;
|
||||
private long amount;
|
||||
private long balanceDelta;
|
||||
|
||||
public AccountChangeInfo(String changeId, String transactionId, String transactionType, long amount, long balanceDelta) {
|
||||
this.changeId = changeId;
|
||||
this.transactionId = transactionId;
|
||||
this.transactionType = transactionType;
|
||||
this.amount = amount;
|
||||
this.balanceDelta = balanceDelta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by cer on 11/21/14.
|
||||
@@ -17,12 +18,18 @@ public class AccountInfo {
|
||||
private long balance;
|
||||
private List<AccountChangeInfo> changes;
|
||||
private Map<String, AccountTransactionInfo> transactions;
|
||||
private Map<String, TransferState> transferStates;
|
||||
private String version;
|
||||
private Date date;
|
||||
|
||||
private AccountInfo() {
|
||||
}
|
||||
|
||||
public AccountInfo(String id, String customerId, String title, String description, long balance, List<AccountChangeInfo> changes, Map<String, AccountTransactionInfo> transactions, String version) {
|
||||
this(id, customerId, title, description, balance, changes, transactions, version, new Date());
|
||||
}
|
||||
|
||||
public AccountInfo(String id, String customerId, String title, String description, long balance, List<AccountChangeInfo> changes, Map<String, AccountTransactionInfo> transactions, String version, Date date) {
|
||||
|
||||
this.id = id;
|
||||
this.customerId = customerId;
|
||||
@@ -32,6 +39,7 @@ public class AccountInfo {
|
||||
this.changes = changes;
|
||||
this.transactions = transactions;
|
||||
this.version = version;
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@@ -65,4 +73,16 @@ public class AccountInfo {
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public Map<String, TransferState> getTransferStates() {
|
||||
return transferStates;
|
||||
}
|
||||
|
||||
public void setTransferStates(Map<String, TransferState> transferStates) {
|
||||
this.transferStates = transferStates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
|
||||
import com.mongodb.WriteResult;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
@@ -9,30 +12,35 @@ import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import static net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.MoneyUtil.toIntegerRepr;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.where;
|
||||
|
||||
public class AccountInfoUpdateService {
|
||||
public class AccountInfoUpdateService {
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private AccountInfoRepository accountInfoRepository;
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
public AccountInfoUpdateService(MongoTemplate mongoTemplate) {
|
||||
public AccountInfoUpdateService(AccountInfoRepository accountInfoRepository, MongoTemplate mongoTemplate) {
|
||||
this.accountInfoRepository = accountInfoRepository;
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void create(String accountId, String customerId, String title, BigDecimal initialBalance, String description, String version) {
|
||||
public void create(String accountId, String customerId, String title, BigDecimal initialBalance, String description, String version) {
|
||||
try {
|
||||
AccountChangeInfo ci = new AccountChangeInfo();
|
||||
ci.setAmount(toIntegerRepr(initialBalance));
|
||||
WriteResult x = mongoTemplate.upsert(new Query(where("id").is(accountId).and("version").exists(false)),
|
||||
new Update()
|
||||
.set("customerId", customerId)
|
||||
.set("title", title)
|
||||
.set("description", description)
|
||||
.set("balance", toIntegerRepr(initialBalance))
|
||||
.push("changes", ci)
|
||||
.set("date", new Date())
|
||||
.set("version", version),
|
||||
AccountInfo.class);
|
||||
logger.info("Saved in mongo");
|
||||
@@ -46,10 +54,10 @@ public class AccountInfoUpdateService {
|
||||
}
|
||||
|
||||
|
||||
public void addTransaction(String eventId, String accountId, AccountTransactionInfo ti) {
|
||||
public void addTransaction(String accountId, AccountTransactionInfo ti) {
|
||||
mongoTemplate.upsert(new Query(where("id").is(accountId)),
|
||||
new Update().
|
||||
set("transactions." + eventId, ti),
|
||||
set("transactions." + ti.getTransactionId(), ti),
|
||||
AccountInfo.class);
|
||||
}
|
||||
|
||||
@@ -63,5 +71,10 @@ public class AccountInfoUpdateService {
|
||||
AccountInfo.class);
|
||||
}
|
||||
|
||||
|
||||
public void updateTransactionStatus(String accountId, String transactionId, TransferState status) {
|
||||
mongoTemplate.upsert(new Query(where("id").is(accountId)),
|
||||
new Update().
|
||||
set("transferStates." + transactionId, status),
|
||||
AccountInfo.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
|
||||
import io.eventuate.CompletableFutureUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class AccountQueryService {
|
||||
|
||||
@@ -13,15 +10,17 @@ public class AccountQueryService {
|
||||
this.accountInfoRepository = accountInfoRepository;
|
||||
}
|
||||
|
||||
public CompletableFuture<AccountInfo> findByAccountId(String accountId) {
|
||||
public AccountInfo findByAccountId(String accountId) {
|
||||
AccountInfo account = accountInfoRepository.findOne(accountId);
|
||||
if (account == null)
|
||||
return CompletableFutureUtil.failedFuture(new AccountNotFoundException(accountId));
|
||||
throw new AccountNotFoundException(accountId);
|
||||
else
|
||||
return CompletableFuture.completedFuture(account);
|
||||
if(account.getTransferStates()!=null)
|
||||
account.getTransactions().stream().forEach(ati -> ati.setStatus(account.getTransferStates().get(ati.getTransactionId())));
|
||||
return account;
|
||||
}
|
||||
|
||||
public CompletableFuture<List<AccountInfo>> findByCustomerId(String customerId) {
|
||||
return CompletableFuture.completedFuture(accountInfoRepository.findByCustomerId(customerId));
|
||||
public List<AccountInfo> findByCustomerId(String customerId) {
|
||||
return accountInfoRepository.findByCustomerId(customerId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,14 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.ac
|
||||
import io.eventuate.DispatchedEvent;
|
||||
import io.eventuate.EventHandlerMethod;
|
||||
import io.eventuate.EventSubscriber;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountChangedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountOpenedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.*;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.CreditRecordedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.DebitRecordedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.FailedDebitRecordedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -56,20 +59,36 @@ public class AccountQueryWorkflow {
|
||||
de.getEvent().getDetails().getDate(),
|
||||
de.getEvent().getDetails().getDescription());
|
||||
|
||||
accountInfoUpdateService.addTransaction(eventId, fromAccountId, ti);
|
||||
accountInfoUpdateService.addTransaction(eventId, toAccountId, ti);
|
||||
accountInfoUpdateService.addTransaction(fromAccountId, ti);
|
||||
accountInfoUpdateService.addTransaction(toAccountId, ti);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void recordDebit(DispatchedEvent<AccountDebitedEvent> de) {
|
||||
String accountId = de.getEntityId();
|
||||
String transactionId = de.getEvent().getTransactionId();
|
||||
|
||||
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.DEBITED);
|
||||
saveChange(de, -1);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void recordCredit(DispatchedEvent<AccountCreditedEvent> de) {
|
||||
String accountId = de.getEntityId();
|
||||
String transactionId = de.getEvent().getTransactionId();
|
||||
|
||||
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.COMPLETED);
|
||||
saveChange(de, +1);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void recordFailed(DispatchedEvent<AccountDebitFailedDueToInsufficientFundsEvent> de) {
|
||||
String accountId = de.getEntityId();
|
||||
String transactionId = de.getEvent().getTransactionId();
|
||||
|
||||
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.FAILED_DUE_TO_INSUFFICIENT_FUNDS);
|
||||
}
|
||||
|
||||
public <T extends AccountChangedEvent> void saveChange(DispatchedEvent<T> de, int delta) {
|
||||
String changeId = de.getEventId().asString();
|
||||
String transactionId = de.getEvent().getTransactionId();
|
||||
|
||||
@@ -18,8 +18,8 @@ public class QuerySideAccountConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccountInfoUpdateService accountInfoUpdateService(MongoTemplate mongoTemplate) {
|
||||
return new AccountInfoUpdateService(mongoTemplate);
|
||||
public AccountInfoUpdateService accountInfoUpdateService(AccountInfoRepository accountInfoRepository, MongoTemplate mongoTemplate) {
|
||||
return new AccountInfoUpdateService(accountInfoRepository, mongoTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -27,8 +27,6 @@ public class QuerySideAccountConfiguration {
|
||||
return new AccountQueryService(accountInfoRepository);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Bean
|
||||
public QuerySideDependencyChecker querysideDependencyChecker(MongoTemplate mongoTemplate) {
|
||||
return new QuerySideDependencyChecker(mongoTemplate);
|
||||
|
||||
@@ -4,6 +4,9 @@ import io.eventuate.javaclient.spring.jdbc.EventuateJdbcEventStoreConfiguration;
|
||||
import io.eventuate.javaclient.spring.jdbc.IdGenerator;
|
||||
import io.eventuate.javaclient.spring.jdbc.IdGeneratorImpl;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -13,11 +16,9 @@ import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -53,14 +54,14 @@ public class AccountInfoUpdateServiceTest {
|
||||
|
||||
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
|
||||
|
||||
AccountInfo accountInfo = accountQueryService.findByAccountId(accountId).get();
|
||||
AccountInfo accountInfo = accountQueryService.findByAccountId(accountId);
|
||||
|
||||
assertEquals(accountId, accountInfo.getId());
|
||||
assertEquals(customerId, accountInfo.getCustomerId());
|
||||
assertEquals(title, accountInfo.getTitle());
|
||||
assertEquals(description, accountInfo.getDescription());
|
||||
assertEquals(initialBalance.longValue() * 100, accountInfo.getBalance());
|
||||
assertTrue(accountInfo.getChanges().isEmpty());
|
||||
assertEquals(1, accountInfo.getChanges().size());
|
||||
assertTrue(accountInfo.getTransactions().isEmpty());
|
||||
assertEquals(version, accountInfo.getVersion());
|
||||
|
||||
@@ -75,19 +76,19 @@ public class AccountInfoUpdateServiceTest {
|
||||
accountInfoUpdateService.updateBalance(accountId, changeId, 500,
|
||||
change);
|
||||
|
||||
accountInfo = accountQueryService.findByAccountId(accountId).get();
|
||||
accountInfo = accountQueryService.findByAccountId(accountId);
|
||||
assertEquals(initialBalance.add(new BigDecimal(5)).longValue() * 100, accountInfo.getBalance());
|
||||
assertFalse(accountInfo.getChanges().isEmpty());
|
||||
|
||||
assertEquals(change, accountInfo.getChanges().get(0));
|
||||
assertEquals(change, accountInfo.getChanges().get(1));
|
||||
|
||||
String eventId = x.genId().asString();
|
||||
|
||||
AccountTransactionInfo ti = new AccountTransactionInfo(transactionId, accountId, accountId, 5, new Date(), "A transfer");
|
||||
|
||||
accountInfoUpdateService.addTransaction(eventId, accountId, ti);
|
||||
accountInfoUpdateService.addTransaction(accountId, ti);
|
||||
|
||||
accountInfo = accountQueryService.findByAccountId(accountId).get();
|
||||
accountInfo = accountQueryService.findByAccountId(accountId);
|
||||
assertFalse(accountInfo.getTransactions().isEmpty());
|
||||
|
||||
assertEquals(ti, accountInfo.getTransactions().get(0));
|
||||
@@ -106,7 +107,43 @@ public class AccountInfoUpdateServiceTest {
|
||||
|
||||
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
|
||||
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateTransactionStatus() {
|
||||
IdGenerator x = new IdGeneratorImpl();
|
||||
String accountId = x.genId().asString();
|
||||
String customerId = x.genId().asString();
|
||||
String version = x.genId().asString();
|
||||
|
||||
String title = "Checking account";
|
||||
BigDecimal initialBalance = new BigDecimal("1345");
|
||||
String description = "Some account";
|
||||
|
||||
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
|
||||
|
||||
String transactionId = x.genId().asString();
|
||||
|
||||
AccountTransactionInfo transactionInfo = new AccountTransactionInfo();
|
||||
transactionInfo.setTransactionId(transactionId);
|
||||
transactionInfo.setStatus(TransferState.INITIAL);
|
||||
|
||||
accountInfoUpdateService.addTransaction(accountId, transactionInfo);
|
||||
|
||||
AccountInfo accountInfo = accountQueryService.findByAccountId(accountId);
|
||||
assertEquals(accountId, accountInfo.getId());
|
||||
assertFalse(accountInfo.getTransactions().isEmpty());
|
||||
assertEquals(1, accountInfo.getTransactions().size());
|
||||
|
||||
assertEquals(TransferState.INITIAL, accountInfo.getTransactions().get(0).getStatus());
|
||||
|
||||
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.COMPLETED);
|
||||
|
||||
accountInfo = accountQueryService.findByAccountId(accountId);
|
||||
assertEquals(accountId, accountInfo.getId());
|
||||
assertFalse(accountInfo.getTransactions().isEmpty());
|
||||
assertEquals(1, accountInfo.getTransactions().size());
|
||||
|
||||
assertEquals(TransferState.COMPLETED, accountInfo.getTransactions().get(0).getStatus());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.GetAccountResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -30,7 +30,7 @@ public class AccountsQuerySideServiceIntegrationTest {
|
||||
private int port;
|
||||
|
||||
private String baseUrl(String path) {
|
||||
return "http://localhost:" + port + "/" + path;
|
||||
return "http://localhost:" + port + "/api" + path;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -4,17 +4,19 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.acc
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountNotFoundException;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountQueryService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountTransactionInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class AccountQueryController {
|
||||
|
||||
private AccountQueryService accountInfoQueryService;
|
||||
@@ -25,21 +27,35 @@ public class AccountQueryController {
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/accounts/{accountId}", method = RequestMethod.GET)
|
||||
public CompletableFuture<GetAccountResponse> get(@PathVariable String accountId) {
|
||||
return accountInfoQueryService.findByAccountId(accountId)
|
||||
.thenApply(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription()));
|
||||
public ResponseEntity<GetAccountResponse> get(@PathVariable String accountId) {
|
||||
AccountInfo accountInfo = accountInfoQueryService.findByAccountId(accountId);
|
||||
return ResponseEntity.ok().body(new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription()));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/accounts", method = RequestMethod.GET)
|
||||
public CompletableFuture<List<GetAccountResponse>> getAccountsForCustomer(@RequestParam("customerId") String customerId) {
|
||||
return accountInfoQueryService.findByCustomerId(customerId)
|
||||
.thenApply(accountInfoList -> accountInfoList.stream().map(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription())).collect(Collectors.toList()));
|
||||
@RequestMapping(value = "/customers/{customerId}/accounts", method = RequestMethod.GET)
|
||||
public ResponseEntity<GetAccountsResponse> getAccountsForCustomer(@PathVariable("customerId") String customerId) {
|
||||
return ResponseEntity.ok().body(
|
||||
new GetAccountsResponse(
|
||||
accountInfoQueryService.findByCustomerId(customerId)
|
||||
.stream()
|
||||
.map(accountInfo -> new GetAccountResponse(
|
||||
accountInfo.getId(),
|
||||
new BigDecimal(accountInfo.getBalance()),
|
||||
accountInfo.getTitle(),
|
||||
accountInfo.getDescription()))
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/accounts/{accountId}/history", method = RequestMethod.GET)
|
||||
public CompletableFuture<List<AccountTransactionInfo>> getTransactionsHistory(@PathVariable String accountId) {
|
||||
return accountInfoQueryService.findByAccountId(accountId)
|
||||
.thenApply(AccountInfo::getTransactions);
|
||||
public ResponseEntity<AccountHistoryResponse> getTransactionsHistory(@PathVariable String accountId) {
|
||||
AccountInfo accountInfo = accountInfoQueryService.findByAccountId(accountId);
|
||||
List<AccountHistoryEntry> historyEntries = new ArrayList<>();
|
||||
historyEntries.add(new AccountOpenInfo(accountInfo.getDate(), AccountHistoryEntry.EntryType.account, accountInfo.getChanges().get(0).getAmount()));
|
||||
accountInfo.getTransactions().forEach(historyEntries::add);
|
||||
|
||||
return ResponseEntity.ok().body(new AccountHistoryResponse(historyEntries));
|
||||
}
|
||||
|
||||
@ResponseStatus(value= HttpStatus.NOT_FOUND, reason="account not found")
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
public class GetAccountResponse {
|
||||
private String accountId;
|
||||
private BigDecimal balance;
|
||||
private String title;
|
||||
private String description;
|
||||
|
||||
public GetAccountResponse() {
|
||||
}
|
||||
|
||||
public GetAccountResponse(String accountId, BigDecimal balance, String title, String description) {
|
||||
this.accountId = accountId;
|
||||
this.balance = balance;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ dependencies {
|
||||
}
|
||||
|
||||
task copyWebStatic(type: Copy) {
|
||||
from "../../prebuilt-web-client"
|
||||
from "../../js-frontend/build"
|
||||
into "build/resources/main/static"
|
||||
}
|
||||
|
||||
|
||||
@@ -11,50 +11,50 @@ import java.util.List;
|
||||
@ConfigurationProperties(prefix = "api.gateway")
|
||||
public class ApiGatewayProperties {
|
||||
|
||||
private List<Endpoint> endpoints;
|
||||
private List<Endpoint> endpoints;
|
||||
|
||||
public static class Endpoint {
|
||||
private String path;
|
||||
private RequestMethod method;
|
||||
private String location;
|
||||
public static class Endpoint {
|
||||
private String path;
|
||||
private RequestMethod method;
|
||||
private String location;
|
||||
|
||||
public Endpoint() {
|
||||
}
|
||||
|
||||
public Endpoint(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public RequestMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(RequestMethod method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
public Endpoint() {
|
||||
}
|
||||
|
||||
public List<Endpoint> getEndpoints() {
|
||||
return endpoints;
|
||||
public Endpoint(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public void setEndpoints(List<Endpoint> endpoints) {
|
||||
this.endpoints = endpoints;
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public RequestMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(RequestMethod method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Endpoint> getEndpoints() {
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
public void setEndpoints(List<Endpoint> endpoints) {
|
||||
this.endpoints = endpoints;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.apigateway;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.eventuate.javaclient.spring.httpstomp.EventuateHttpStompClientConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.AuthConfiguration;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
@@ -27,24 +26,24 @@ import java.util.Collections;
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
@Import({EventuateHttpStompClientConfiguration.class, AuthConfiguration.class})
|
||||
@Import({AuthConfiguration.class})
|
||||
@EnableConfigurationProperties({ApiGatewayProperties.class})
|
||||
public class ApiGatewayServiceConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpMessageConverters converters) {
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpMessageConverters converters) {
|
||||
|
||||
// we have to define Apache HTTP client to use the PATCH verb
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/json"));
|
||||
converter.setObjectMapper(new ObjectMapper());
|
||||
// we have to define Apache HTTP client to use the PATCH verb
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/json"));
|
||||
converter.setObjectMapper(new ObjectMapper());
|
||||
|
||||
HttpClient httpClient = HttpClients.createDefault();
|
||||
RestTemplate restTemplate = new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(converter));
|
||||
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
|
||||
HttpClient httpClient = HttpClients.createDefault();
|
||||
RestTemplate restTemplate = new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(converter));
|
||||
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
|
||||
|
||||
restTemplate.setErrorHandler(new RestTemplateErrorHandler());
|
||||
restTemplate.setErrorHandler(new RestTemplateErrorHandler());
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import java.io.IOException;
|
||||
|
||||
public class RestTemplateErrorHandler implements ResponseErrorHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RestTemplateErrorHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(RestTemplateErrorHandler.class);
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
log.error("Response error: {} {}", response.getStatusCode(), response.getStatusText());
|
||||
}
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
log.error("Response error: {} {}", response.getStatusCode(), response.getStatusText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return RestUtil.isError(response.getStatusCode());
|
||||
}
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return RestUtil.isError(response.getStatusCode());
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,9 @@ import org.springframework.http.HttpStatus;
|
||||
*/
|
||||
public class RestUtil {
|
||||
|
||||
public static boolean isError(HttpStatus status) {
|
||||
HttpStatus.Series series = status.series();
|
||||
return (HttpStatus.Series.CLIENT_ERROR.equals(series)
|
||||
|| HttpStatus.Series.SERVER_ERROR.equals(series));
|
||||
}
|
||||
public static boolean isError(HttpStatus status) {
|
||||
HttpStatus.Series series = status.series();
|
||||
return (HttpStatus.Series.CLIENT_ERROR.equals(series)
|
||||
|| HttpStatus.Series.SERVER_ERROR.equals(series));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.ApiGateway
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.ContentRequestTransformer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.HeadersRequestTransformer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.URLRequestTransformer;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
@@ -12,7 +13,12 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
|
||||
|
||||
@@ -24,8 +30,10 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 15.01.16.
|
||||
@@ -33,43 +41,51 @@ import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
@RestController
|
||||
public class GatewayController {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private ApiGatewayProperties apiGatewayProperties;
|
||||
@Autowired
|
||||
private ApiGatewayProperties apiGatewayProperties;
|
||||
|
||||
private HttpClient httpClient;
|
||||
private HttpClient httpClient;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
|
||||
httpClient = HttpClients.custom()
|
||||
.setConnectionManager(cm)
|
||||
.build();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/**", method = {GET, POST})
|
||||
public String proxyRequest(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, IOException, URISyntaxException {
|
||||
HttpUriRequest proxiedRequest = createHttpUriRequest(request);
|
||||
log.info("request: {}", proxiedRequest);
|
||||
HttpResponse proxiedResponse = httpClient.execute(proxiedRequest);
|
||||
return read(proxiedResponse.getEntity().getContent());
|
||||
}
|
||||
|
||||
private HttpUriRequest createHttpUriRequest(HttpServletRequest request) throws URISyntaxException, NoSuchRequestHandlingMethodException, IOException {
|
||||
URLRequestTransformer urlRequestTransformer = new URLRequestTransformer(apiGatewayProperties);
|
||||
ContentRequestTransformer contentRequestTransformer = new ContentRequestTransformer();
|
||||
HeadersRequestTransformer headersRequestTransformer = new HeadersRequestTransformer();
|
||||
headersRequestTransformer.setPredecessor(contentRequestTransformer);
|
||||
contentRequestTransformer.setPredecessor(urlRequestTransformer);
|
||||
|
||||
return headersRequestTransformer.transform(request).build();
|
||||
}
|
||||
|
||||
private String read(InputStream input) throws IOException {
|
||||
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
|
||||
return buffer.lines().collect(Collectors.joining("\n"));
|
||||
}
|
||||
httpClient = HttpClients.custom()
|
||||
.setConnectionManager(cm)
|
||||
.build();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/api/**", method = {GET, POST})
|
||||
@ResponseBody
|
||||
public ResponseEntity<String> proxyRequest(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, IOException, URISyntaxException {
|
||||
HttpUriRequest proxiedRequest = createHttpUriRequest(request);
|
||||
logger.info("request: {}", proxiedRequest);
|
||||
HttpResponse proxiedResponse = httpClient.execute(proxiedRequest);
|
||||
logger.info("Response {}", proxiedResponse.getStatusLine().getStatusCode());
|
||||
return new ResponseEntity<>(read(proxiedResponse.getEntity().getContent()), processHeaders(proxiedResponse.getAllHeaders()), HttpStatus.valueOf(proxiedResponse.getStatusLine().getStatusCode()));
|
||||
}
|
||||
|
||||
private HttpHeaders processHeaders(Header[] headers) {
|
||||
HttpHeaders result = new HttpHeaders();
|
||||
Stream.of(headers).filter(h -> h.getName().equalsIgnoreCase("Content-Type")).forEach( h -> result.set(h.getName(), h.getValue()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private HttpUriRequest createHttpUriRequest(HttpServletRequest request) throws URISyntaxException, NoSuchRequestHandlingMethodException, IOException {
|
||||
URLRequestTransformer urlRequestTransformer = new URLRequestTransformer(apiGatewayProperties);
|
||||
ContentRequestTransformer contentRequestTransformer = new ContentRequestTransformer();
|
||||
HeadersRequestTransformer headersRequestTransformer = new HeadersRequestTransformer();
|
||||
headersRequestTransformer.setPredecessor(contentRequestTransformer);
|
||||
contentRequestTransformer.setPredecessor(urlRequestTransformer);
|
||||
|
||||
return headersRequestTransformer.transform(request).build();
|
||||
}
|
||||
|
||||
private String read(InputStream input) throws IOException {
|
||||
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
|
||||
return buffer.lines().collect(Collectors.joining("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.springframework.boot.SpringApplication;
|
||||
* Created by Main on 19.01.2016.
|
||||
*/
|
||||
public class ApiGatewayServiceMain {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ApiGatewayServiceConfiguration.class, args);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ApiGatewayServiceConfiguration.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class ContentRequestTransformer extends ProxyRequestTransformer {
|
||||
|
||||
@Override
|
||||
public RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException, IOException {
|
||||
RequestBuilder requestBuilder = predecessor.transform(request);
|
||||
@Override
|
||||
public RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException, IOException {
|
||||
RequestBuilder requestBuilder = predecessor.transform(request);
|
||||
|
||||
String requestContent = request.getReader().lines().collect(Collectors.joining(""));
|
||||
if(!requestContent.isEmpty()) {
|
||||
StringEntity entity = new StringEntity(requestContent, ContentType.APPLICATION_JSON);
|
||||
requestBuilder.setEntity(entity);
|
||||
}
|
||||
|
||||
return requestBuilder;
|
||||
String requestContent = request.getReader().lines().collect(Collectors.joining(""));
|
||||
if (!requestContent.isEmpty()) {
|
||||
StringEntity entity = new StringEntity(requestContent, ContentType.APPLICATION_JSON);
|
||||
requestBuilder.setEntity(entity);
|
||||
}
|
||||
|
||||
return requestBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,20 +13,19 @@ import java.util.Enumeration;
|
||||
*/
|
||||
public class HeadersRequestTransformer extends ProxyRequestTransformer {
|
||||
|
||||
@Override
|
||||
public RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException, IOException {
|
||||
RequestBuilder requestBuilder = predecessor.transform(request);
|
||||
|
||||
@Override
|
||||
public RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException, IOException {
|
||||
RequestBuilder requestBuilder = predecessor.transform(request);
|
||||
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
String headerValue = request.getHeader(headerName);
|
||||
if(headerName.equals("x-access-token")) {
|
||||
requestBuilder.addHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
return requestBuilder;
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
String headerValue = request.getHeader(headerName);
|
||||
if (headerName.equals("x-access-token")) {
|
||||
requestBuilder.addHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
return requestBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ import java.net.URISyntaxException;
|
||||
*/
|
||||
public abstract class ProxyRequestTransformer {
|
||||
|
||||
protected ProxyRequestTransformer predecessor;
|
||||
protected ProxyRequestTransformer predecessor;
|
||||
|
||||
public abstract RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException, IOException;
|
||||
public abstract RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException, IOException;
|
||||
|
||||
public void setPredecessor(ProxyRequestTransformer transformer) {
|
||||
this.predecessor = transformer;
|
||||
};
|
||||
public void setPredecessor(ProxyRequestTransformer transformer) {
|
||||
this.predecessor = transformer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,35 +14,35 @@ import java.net.URISyntaxException;
|
||||
*/
|
||||
public class URLRequestTransformer extends ProxyRequestTransformer {
|
||||
|
||||
private ApiGatewayProperties apiGatewayProperties;
|
||||
private ApiGatewayProperties apiGatewayProperties;
|
||||
|
||||
public URLRequestTransformer(ApiGatewayProperties apiGatewayProperties) {
|
||||
this.apiGatewayProperties = apiGatewayProperties;
|
||||
public URLRequestTransformer(ApiGatewayProperties apiGatewayProperties) {
|
||||
this.apiGatewayProperties = apiGatewayProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException {
|
||||
String requestURI = request.getRequestURI();
|
||||
URI uri;
|
||||
if (request.getQueryString() != null && !request.getQueryString().isEmpty()) {
|
||||
uri = new URI(getServiceUrl(requestURI, request) + "?" + request.getQueryString());
|
||||
} else {
|
||||
uri = new URI(getServiceUrl(requestURI, request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder transform(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, URISyntaxException {
|
||||
String requestURI = request.getRequestURI();
|
||||
URI uri;
|
||||
if (request.getQueryString() != null && !request.getQueryString().isEmpty()) {
|
||||
uri = new URI(getServiceUrl(requestURI, request) + "?" + request.getQueryString());
|
||||
} else {
|
||||
uri = new URI(getServiceUrl(requestURI, request));
|
||||
}
|
||||
RequestBuilder rb = RequestBuilder.create(request.getMethod());
|
||||
rb.setUri(uri);
|
||||
return rb;
|
||||
}
|
||||
|
||||
RequestBuilder rb = RequestBuilder.create(request.getMethod());
|
||||
rb.setUri(uri);
|
||||
return rb;
|
||||
}
|
||||
private String getServiceUrl(String requestURI, HttpServletRequest httpServletRequest) throws NoSuchRequestHandlingMethodException {
|
||||
|
||||
private String getServiceUrl(String requestURI, HttpServletRequest httpServletRequest) throws NoSuchRequestHandlingMethodException {
|
||||
|
||||
ApiGatewayProperties.Endpoint endpoint =
|
||||
apiGatewayProperties.getEndpoints().stream()
|
||||
.filter(e ->
|
||||
requestURI.matches(e.getPath()) && e.getMethod() == RequestMethod.valueOf(httpServletRequest.getMethod())
|
||||
)
|
||||
.findFirst().orElseThrow(() -> new NoSuchRequestHandlingMethodException(httpServletRequest));
|
||||
return endpoint.getLocation() + requestURI;
|
||||
}
|
||||
ApiGatewayProperties.Endpoint endpoint =
|
||||
apiGatewayProperties.getEndpoints().stream()
|
||||
.filter(e ->
|
||||
requestURI.matches(e.getPath()) && e.getMethod() == RequestMethod.valueOf(httpServletRequest.getMethod())
|
||||
)
|
||||
.findFirst().orElseThrow(() -> new NoSuchRequestHandlingMethodException(httpServletRequest));
|
||||
return endpoint.getLocation() + requestURI;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,21 @@ customers.queryside.service.host=localhost
|
||||
transfers.commandside.service.host=localhost
|
||||
|
||||
|
||||
api.gateway.endpoints[0].path=[/]*accounts.*
|
||||
api.gateway.endpoints[0].path=[/]*api/accounts.*
|
||||
api.gateway.endpoints[0].method=GET
|
||||
api.gateway.endpoints[0].location=http://${accounts.queryside.service.host}:8080
|
||||
api.gateway.endpoints[1].path=[/]*accounts.*
|
||||
api.gateway.endpoints[1].method=POST
|
||||
api.gateway.endpoints[1].location=http://${accounts.commandside.service.host}:8080
|
||||
api.gateway.endpoints[2].path=[/]*customers.*
|
||||
api.gateway.endpoints[2].method=GET
|
||||
api.gateway.endpoints[2].location=http://${customers.queryside.service.host}:8080
|
||||
api.gateway.endpoints[3].path=[/]*customers.*
|
||||
api.gateway.endpoints[3].method=POST
|
||||
api.gateway.endpoints[3].location=http://${customers.commandside.service.host}:8080
|
||||
api.gateway.endpoints[4].path=[/]*transfers.*
|
||||
api.gateway.endpoints[1].path=[/]*api/customers.*/accounts
|
||||
api.gateway.endpoints[1].method=GET
|
||||
api.gateway.endpoints[1].location=http://${accounts.queryside.service.host}:8080
|
||||
api.gateway.endpoints[2].path=[/]*api/accounts.*
|
||||
api.gateway.endpoints[2].method=POST
|
||||
api.gateway.endpoints[2].location=http://${accounts.commandside.service.host}:8080
|
||||
api.gateway.endpoints[3].path=[/]*api/customers.*
|
||||
api.gateway.endpoints[3].method=GET
|
||||
api.gateway.endpoints[3].location=http://${customers.queryside.service.host}:8080
|
||||
api.gateway.endpoints[4].path=[/]*api/customers.*
|
||||
api.gateway.endpoints[4].method=POST
|
||||
api.gateway.endpoints[4].location=http://${transfers.commandside.service.host}:8080
|
||||
api.gateway.endpoints[4].location=http://${customers.commandside.service.host}:8080
|
||||
api.gateway.endpoints[5].path=[/]*api/transfers.*
|
||||
api.gateway.endpoints[5].method=POST
|
||||
api.gateway.endpoints[5].location=http://${transfers.commandside.service.host}:8080
|
||||
@@ -14,6 +14,11 @@
|
||||
</root>
|
||||
<logger name="org.springframework" level='info'>
|
||||
</logger>
|
||||
<logger name="net.chrisrichardson.eventstore.client" level='info'>
|
||||
|
||||
<logger name="net.chrisrichardson.eventstore.javaexamples.banking" level='info'>
|
||||
</logger>
|
||||
|
||||
<logger name="io.eventuate" level='debug'>
|
||||
</logger>
|
||||
|
||||
</configuration>
|
||||
@@ -7,7 +7,7 @@ dependencies {
|
||||
testCompile project(":accounts-query-side-backend")
|
||||
testCompile project(":customers-command-side-backend")
|
||||
testCompile project(":customers-query-side-backend")
|
||||
testCompile project(":testutil-customers")
|
||||
testCompile project(":testutil")
|
||||
testCompile "junit:junit:4.11"
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"
|
||||
|
||||
@@ -6,6 +6,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.t
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
||||
@Configuration
|
||||
@Import({AccountConfiguration.class, MoneyTransferConfiguration.class, EventuateJdbcEventStoreConfiguration.class})
|
||||
|
||||
@@ -6,7 +6,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.a
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransfer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.TransferState;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@@ -23,7 +23,7 @@ import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil
|
||||
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes=BankingTestConfiguration.class)
|
||||
@SpringApplicationConfiguration(classes = BankingTestConfiguration.class)
|
||||
@IntegrationTest
|
||||
public class MoneyTransferIntegrationTest {
|
||||
|
||||
@@ -35,11 +35,11 @@ public class MoneyTransferIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private EventuateAggregateStore eventStore;
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldTransferMoney() {
|
||||
final EntityWithIdAndVersion<Account> fromAccount= await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
|
||||
final EntityWithIdAndVersion<Account> fromAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
|
||||
|
||||
final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300), ""));
|
||||
|
||||
@@ -49,22 +49,22 @@ public class MoneyTransferIntegrationTest {
|
||||
new BigDecimal(80))));
|
||||
|
||||
|
||||
eventually (
|
||||
eventually(
|
||||
() -> eventStore.find(Account.class, fromAccount.getEntityId()),
|
||||
account -> Assert.assertEquals(new BigDecimal(70), account.getEntity().getBalance()));
|
||||
|
||||
eventually (
|
||||
eventually(
|
||||
() -> eventStore.find(Account.class, toAccount.getEntityId()),
|
||||
account -> Assert.assertEquals(new BigDecimal(380), account.getEntity().getBalance()));
|
||||
|
||||
eventually (
|
||||
eventually(
|
||||
() -> eventStore.find(MoneyTransfer.class, transaction.getEntityId()),
|
||||
updatedTransaction -> Assert.assertEquals(TransferState.COMPLETED, updatedTransaction.getEntity().getState()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailDueToInsufficientFunds() {
|
||||
final EntityWithIdAndVersion<Account> fromAccount= await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
|
||||
final EntityWithIdAndVersion<Account> fromAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
|
||||
|
||||
final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300), ""));
|
||||
|
||||
@@ -74,15 +74,15 @@ public class MoneyTransferIntegrationTest {
|
||||
new BigDecimal(200))));
|
||||
|
||||
|
||||
eventually (
|
||||
eventually(
|
||||
() -> eventStore.find(MoneyTransfer.class, transaction.getEntityId()),
|
||||
updatedTransaction -> Assert.assertEquals(TransferState.FAILED_DUE_TO_INSUFFICIENT_FUNDS, updatedTransaction.getEntity().getState()));
|
||||
|
||||
eventually (
|
||||
eventually(
|
||||
() -> eventStore.find(Account.class, fromAccount.getEntityId()),
|
||||
account -> Assert.assertEquals(new BigDecimal(150), account.getEntity().getBalance()));
|
||||
|
||||
eventually (
|
||||
eventually(
|
||||
() -> eventStore.find(Account.class, toAccount.getEntityId()),
|
||||
account -> Assert.assertEquals(new BigDecimal(300), account.getEntity().getBalance()));
|
||||
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
|
||||
import io.eventuate.EntityWithIdAndVersion;
|
||||
import io.eventuate.EntityWithMetadata;
|
||||
import io.eventuate.EventuateAggregateStore;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.Account;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransfer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.TransferState;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -18,9 +15,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import rx.Observable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.await;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
|
||||
@@ -59,10 +56,10 @@ public class AccountQuerySideIntegrationTest {
|
||||
updatedTransaction -> Assert.assertEquals(TransferState.COMPLETED, updatedTransaction.getEntity().getState()));
|
||||
|
||||
eventually(
|
||||
() -> accountQueryService.findByAccountId(fromAccount.getEntityId()),
|
||||
accountInfo -> Assert.assertEquals(70*100, accountInfo.getBalance()));
|
||||
() -> CompletableFuture.completedFuture(accountQueryService.findByAccountId(fromAccount.getEntityId())),
|
||||
accountInfo -> Assert.assertEquals(70 * 100, accountInfo.getBalance()));
|
||||
eventually(
|
||||
() -> accountQueryService.findByAccountId(toAccount.getEntityId()),
|
||||
accountInfo -> Assert.assertEquals(380*100, accountInfo.getBalance()));
|
||||
() -> CompletableFuture.completedFuture(accountQueryService.findByAccountId(toAccount.getEntityId())),
|
||||
accountInfo -> Assert.assertEquals(380 * 100, accountInfo.getBalance()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateCustomerInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateToAccountInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.await;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateCustomerInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateToAccountInfo;
|
||||
|
||||
/**
|
||||
* Created by Main on 10.02.2016.
|
||||
@@ -32,43 +32,43 @@ import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customer
|
||||
@IntegrationTest
|
||||
public class CustomerQuerySideIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private CustomerService customerService;
|
||||
@Autowired
|
||||
private CustomerService customerService;
|
||||
|
||||
@Autowired
|
||||
private CustomerQueryService customerQueryService;
|
||||
@Autowired
|
||||
private CustomerQueryService customerQueryService;
|
||||
|
||||
@Autowired
|
||||
@Autowired
|
||||
private EventuateAggregateStore eventStore;
|
||||
|
||||
@Test
|
||||
public void shouldCreateCustomerAndAddToAccount() throws Exception {
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
EntityWithIdAndVersion<Customer> customer = await(customerService.createCustomer(customerInfo));
|
||||
@Test
|
||||
public void shouldCreateCustomerAndAddToAccount() throws Exception {
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
EntityWithIdAndVersion<Customer> customer = await(customerService.createCustomer(customerInfo));
|
||||
|
||||
ToAccountInfo toAccountInfo = generateToAccountInfo();
|
||||
EntityWithIdAndVersion<Customer> customerWithNewAccount = await(customerService.addToAccount(customer.getEntityId(), toAccountInfo));
|
||||
ToAccountInfo toAccountInfo = generateToAccountInfo();
|
||||
EntityWithIdAndVersion<Customer> customerWithNewAccount = await(customerService.addToAccount(customer.getEntityId(), toAccountInfo));
|
||||
|
||||
eventually(
|
||||
new Producer<QuerySideCustomer>() {
|
||||
@Override
|
||||
public CompletableFuture<QuerySideCustomer> produce() {
|
||||
return customerQueryService.findByCustomerId(customer.getEntityId());
|
||||
}
|
||||
},
|
||||
new Verifier<QuerySideCustomer>() {
|
||||
@Override
|
||||
public void verify(QuerySideCustomer querySideCustomer) {
|
||||
Assert.assertEquals(customerInfo.getName(), querySideCustomer.getName());
|
||||
Assert.assertEquals(customerInfo.getSsn(), querySideCustomer.getSsn());
|
||||
Assert.assertEquals(customerInfo.getEmail(), querySideCustomer.getEmail());
|
||||
Assert.assertEquals(customerInfo.getPhoneNumber(), querySideCustomer.getPhoneNumber());
|
||||
Assert.assertEquals(customerInfo.getAddress(), querySideCustomer.getAddress());
|
||||
eventually(
|
||||
new Producer<QuerySideCustomer>() {
|
||||
@Override
|
||||
public CompletableFuture<QuerySideCustomer> produce() {
|
||||
return customerQueryService.findByCustomerId(customer.getEntityId());
|
||||
}
|
||||
},
|
||||
new Verifier<QuerySideCustomer>() {
|
||||
@Override
|
||||
public void verify(QuerySideCustomer querySideCustomer) {
|
||||
Assert.assertEquals(customerInfo.getName(), querySideCustomer.getName());
|
||||
Assert.assertEquals(customerInfo.getSsn(), querySideCustomer.getSsn());
|
||||
Assert.assertEquals(customerInfo.getEmail(), querySideCustomer.getEmail());
|
||||
Assert.assertEquals(customerInfo.getPhoneNumber(), querySideCustomer.getPhoneNumber());
|
||||
Assert.assertEquals(customerInfo.getAddress(), querySideCustomer.getAddress());
|
||||
|
||||
Assert.assertNotNull(querySideCustomer.getToAccounts());
|
||||
Assert.assertFalse(querySideCustomer.getToAccounts().isEmpty());
|
||||
Assert.assertEquals(querySideCustomer.getToAccounts().get("11111111-11111111"), toAccountInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
Assert.assertNotNull(querySideCustomer.getToAccounts());
|
||||
Assert.assertFalse(querySideCustomer.getToAccounts().isEmpty());
|
||||
Assert.assertEquals(querySideCustomer.getToAccounts().get("11111111-11111111"), toAccountInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile project(":common-auth")
|
||||
compile project(":common-customers")
|
||||
compile project(":common")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
compile "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
||||
|
||||
@@ -28,37 +28,38 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@RequestMapping("/api")
|
||||
public class AuthController {
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private CustomerAuthService customerAuthService;
|
||||
@Autowired
|
||||
private CustomerAuthService customerAuthService;
|
||||
|
||||
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@RequestMapping(value = "/login", method = POST)
|
||||
public ResponseEntity<QuerySideCustomer> doAuth(@RequestBody @Valid AuthRequest request) throws IOException {
|
||||
QuerySideCustomer customer = customerAuthService.findByEmail(request.getEmail());
|
||||
@RequestMapping(value = "/login", method = POST)
|
||||
public ResponseEntity<QuerySideCustomer> doAuth(@RequestBody @Valid AuthRequest request) throws IOException {
|
||||
QuerySideCustomer customer = customerAuthService.findByEmail(request.getEmail());
|
||||
|
||||
Token token = tokenService.allocateToken(objectMapper.writeValueAsString(new User(request.getEmail())));
|
||||
return ResponseEntity.status(HttpStatus.OK).header("access-token", token.getKey())
|
||||
.body(customer);
|
||||
}
|
||||
Token token = tokenService.allocateToken(objectMapper.writeValueAsString(new User(request.getEmail())));
|
||||
return ResponseEntity.status(HttpStatus.OK).header("access-token", token.getKey())
|
||||
.body(customer);
|
||||
}
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(IncorrectResultSizeDataAccessException.class)
|
||||
public ErrorResponse customersNotFound() {
|
||||
return new ErrorResponse("Customer not found");
|
||||
}
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(IncorrectResultSizeDataAccessException.class)
|
||||
public ErrorResponse customersNotFound() {
|
||||
return new ErrorResponse("Customer not found");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/user", method = GET)
|
||||
public ResponseEntity<QuerySideCustomer> getCurrentUser() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
@RequestMapping(value = "/user", method = GET)
|
||||
public ResponseEntity<QuerySideCustomer> getCurrentUser() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK).body(customerAuthService.findByEmail(auth.getName()));
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.OK).body(customerAuthService.findByEmail(auth.getName()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,22 +8,22 @@ import org.hibernate.validator.constraints.NotBlank;
|
||||
*/
|
||||
public class AuthRequest {
|
||||
|
||||
@NotBlank
|
||||
@Email
|
||||
private String email;
|
||||
@NotBlank
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
public AuthRequest() {
|
||||
}
|
||||
public AuthRequest() {
|
||||
}
|
||||
|
||||
public AuthRequest(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
public AuthRequest(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,20 @@ package net.chrisrichardson.eventstore.javaexamples.banking.commonauth.model;
|
||||
*/
|
||||
public class ErrorResponse {
|
||||
|
||||
private String message;
|
||||
private String message;
|
||||
|
||||
public ErrorResponse() {
|
||||
}
|
||||
public ErrorResponse() {
|
||||
}
|
||||
|
||||
public ErrorResponse(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
public ErrorResponse(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile project(":common-customers")
|
||||
compile project(":common")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
compile "org.springframework.boot:spring-boot-starter-data-mongodb:$springBootVersion"
|
||||
|
||||
@@ -32,66 +32,66 @@ import java.security.SecureRandom;
|
||||
@EnableConfigurationProperties({AuthProperties.class})
|
||||
public class AuthConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private AuthProperties securityProperties;
|
||||
@Autowired
|
||||
private AuthProperties securityProperties;
|
||||
|
||||
@Autowired
|
||||
private TokenAuthenticationService tokenAuthenticationService;
|
||||
@Autowired
|
||||
private TokenAuthenticationService tokenAuthenticationService;
|
||||
|
||||
@Autowired
|
||||
CustomerAuthService customerAuthService;
|
||||
@Autowired
|
||||
CustomerAuthService customerAuthService;
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
//auth.inMemoryAuthentication();
|
||||
auth.userDetailsService(userDetailsServiceBean());
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
//auth.inMemoryAuthentication();
|
||||
auth.userDetailsService(userDetailsServiceBean());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() {
|
||||
return email -> {
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() {
|
||||
return email -> {
|
||||
/* QuerySideCustomer customer = customerAuthService.findByEmail(email);
|
||||
if (customer != null) {
|
||||
return new User(email);
|
||||
} else {
|
||||
throw new UsernameNotFoundException(String.format("could not find the customer '%s'", email));
|
||||
}*/
|
||||
//authorize everyone with basic authentication
|
||||
return new User(email, "", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("USER"));
|
||||
//authorize everyone with basic authentication
|
||||
return new User(email, "", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("USER"));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomerAuthService customerAuthService(CustomerAuthRepository customerAuthRepository) {
|
||||
return new CustomerAuthService(customerAuthRepository);
|
||||
}
|
||||
@Bean
|
||||
public CustomerAuthService customerAuthService(CustomerAuthRepository customerAuthRepository) {
|
||||
return new CustomerAuthService(customerAuthRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable()
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/index.html", "/", "/**.js", "/**.css").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/v2/api-docs").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/customers", "/login").permitAll()
|
||||
.anyRequest().authenticated().and()
|
||||
.addFilterAfter(new StatelessAuthenticationFilter(tokenAuthenticationService), BasicAuthenticationFilter.class);
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable()
|
||||
.httpBasic().and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/index.html", "/", "/**.js", "/**.css").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/v2/api-docs").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/api/customers", "/api/login").permitAll()
|
||||
.anyRequest().authenticated().and()
|
||||
.addFilterAfter(new StatelessAuthenticationFilter(tokenAuthenticationService), BasicAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TokenService tokenService() {
|
||||
KeyBasedPersistenceTokenService res = new KeyBasedPersistenceTokenService();
|
||||
res.setSecureRandom(new SecureRandom());
|
||||
res.setServerSecret(securityProperties.getServerSecret());
|
||||
res.setServerInteger(securityProperties.getServerInteger());
|
||||
@Bean
|
||||
public TokenService tokenService() {
|
||||
KeyBasedPersistenceTokenService res = new KeyBasedPersistenceTokenService();
|
||||
res.setSecureRandom(new SecureRandom());
|
||||
res.setServerSecret(securityProperties.getServerSecret());
|
||||
res.setServerInteger(securityProperties.getServerInteger());
|
||||
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,22 +7,22 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
*/
|
||||
@ConfigurationProperties(locations = "classpath:auth.properties", ignoreUnknownFields = false, prefix = "auth")
|
||||
public class AuthProperties {
|
||||
private String serverSecret;
|
||||
private Integer serverInteger;
|
||||
private String serverSecret;
|
||||
private Integer serverInteger;
|
||||
|
||||
public String getServerSecret() {
|
||||
return serverSecret;
|
||||
}
|
||||
public String getServerSecret() {
|
||||
return serverSecret;
|
||||
}
|
||||
|
||||
public void setServerSecret(String serverSecret) {
|
||||
this.serverSecret = serverSecret;
|
||||
}
|
||||
public void setServerSecret(String serverSecret) {
|
||||
this.serverSecret = serverSecret;
|
||||
}
|
||||
|
||||
public Integer getServerInteger() {
|
||||
return serverInteger;
|
||||
}
|
||||
public Integer getServerInteger() {
|
||||
return serverInteger;
|
||||
}
|
||||
|
||||
public void setServerInteger(Integer serverInteger) {
|
||||
this.serverInteger = serverInteger;
|
||||
}
|
||||
public void setServerInteger(Integer serverInteger) {
|
||||
this.serverInteger = serverInteger;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ import java.util.List;
|
||||
|
||||
interface CustomerAuthRepository extends MongoRepository<QuerySideCustomer, String> {
|
||||
|
||||
List<QuerySideCustomer> findByEmail(String email);
|
||||
}
|
||||
List<QuerySideCustomer> findByEmail(String email);
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package net.chrisrichardson.eventstore.javaexamples.banking.commonauth;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -10,20 +9,20 @@ import java.util.List;
|
||||
* Created by Main on 15.02.2016.
|
||||
*/
|
||||
public class CustomerAuthService {
|
||||
private CustomerAuthRepository customerAuthRepository;
|
||||
private CustomerAuthRepository customerAuthRepository;
|
||||
|
||||
public CustomerAuthService(CustomerAuthRepository customerAuthRepository) {
|
||||
this.customerAuthRepository = customerAuthRepository;
|
||||
}
|
||||
public CustomerAuthService(CustomerAuthRepository customerAuthRepository) {
|
||||
this.customerAuthRepository = customerAuthRepository;
|
||||
}
|
||||
|
||||
public QuerySideCustomer findByEmail(String email){
|
||||
List<QuerySideCustomer> customers = customerAuthRepository.findByEmail(email);
|
||||
if (customers.isEmpty())
|
||||
throw new EmptyResultDataAccessException(1);
|
||||
//TODO: add unique email constraint
|
||||
public QuerySideCustomer findByEmail(String email) {
|
||||
List<QuerySideCustomer> customers = customerAuthRepository.findByEmail(email);
|
||||
if (customers.isEmpty())
|
||||
throw new EmptyResultDataAccessException(1);
|
||||
//TODO: add unique email constraint
|
||||
/* else if(customers.size()>1)
|
||||
throw new IncorrectResultSizeDataAccessException(1, customers.size());*/
|
||||
else
|
||||
return customers.get(0);
|
||||
}
|
||||
else
|
||||
return customers.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,26 +18,26 @@ import java.io.IOException;
|
||||
@Service
|
||||
public class TokenAuthenticationService {
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
private static final String AUTH_HEADER_NAME = "access-token";
|
||||
private static final long DAY = 1000 * 60 * 60 * 24;
|
||||
private static final String AUTH_HEADER_NAME = "access-token";
|
||||
private static final long DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Authentication getAuthentication(HttpServletRequest request) throws IOException {
|
||||
final String tokenString = request.getHeader(AUTH_HEADER_NAME);
|
||||
public Authentication getAuthentication(HttpServletRequest request) throws IOException {
|
||||
final String tokenString = request.getHeader(AUTH_HEADER_NAME);
|
||||
|
||||
if (tokenString != null) {
|
||||
Token token = tokenService.verifyToken(tokenString);
|
||||
final User user = mapper.readValue(token.getExtendedInformation(), User.class);
|
||||
if (tokenString != null) {
|
||||
Token token = tokenService.verifyToken(tokenString);
|
||||
final User user = mapper.readValue(token.getExtendedInformation(), User.class);
|
||||
|
||||
if (user != null && (System.currentTimeMillis() - token.getKeyCreationTime()) < DAY) {
|
||||
return new UserAuthentication(user);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (user != null && (System.currentTimeMillis() - token.getKeyCreationTime()) < DAY) {
|
||||
return new UserAuthentication(user);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@ import java.io.IOException;
|
||||
*/
|
||||
public class StatelessAuthenticationFilter extends GenericFilterBean {
|
||||
|
||||
private final TokenAuthenticationService tokenAuthenticationService;
|
||||
private final TokenAuthenticationService tokenAuthenticationService;
|
||||
|
||||
public StatelessAuthenticationFilter(TokenAuthenticationService taService) {
|
||||
this.tokenAuthenticationService = taService;
|
||||
}
|
||||
public StatelessAuthenticationFilter(TokenAuthenticationService taService) {
|
||||
this.tokenAuthenticationService = taService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
if (SecurityContextHolder.getContext().getAuthentication()==null) {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
tokenAuthenticationService.getAuthentication((HttpServletRequest) req));
|
||||
}
|
||||
chain.doFilter(req, res);
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
if (SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
tokenAuthenticationService.getAuthentication((HttpServletRequest) req));
|
||||
}
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
}
|
||||
@@ -16,63 +16,63 @@ import java.util.Set;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class User implements UserDetails {
|
||||
|
||||
private String email;
|
||||
private String email;
|
||||
|
||||
public User() {
|
||||
}
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
public User(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.email = username;
|
||||
}
|
||||
public void setUsername(String username) {
|
||||
this.email = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("USER");
|
||||
Set<GrantedAuthority> res = new HashSet<GrantedAuthority>();
|
||||
res.add(authority);
|
||||
return res;
|
||||
}
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("USER");
|
||||
Set<GrantedAuthority> res = new HashSet<GrantedAuthority>();
|
||||
res.add(authority);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.email;
|
||||
}
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,45 +10,45 @@ import java.util.Collection;
|
||||
*/
|
||||
public class UserAuthentication implements Authentication {
|
||||
|
||||
private final User user;
|
||||
private boolean authenticated = true;
|
||||
private final User user;
|
||||
private boolean authenticated = true;
|
||||
|
||||
public UserAuthentication(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
public UserAuthentication(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return user.getUsername();
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return user.getAuthorities();
|
||||
}
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return user.getAuthorities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return user.getPassword();
|
||||
}
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return user.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getDetails() {
|
||||
return user;
|
||||
}
|
||||
@Override
|
||||
public User getDetails() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return user.getUsername();
|
||||
}
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
@Override
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils;
|
||||
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Created by Main on 18.02.2016.
|
||||
*/
|
||||
public class BasicAuthUtils {
|
||||
|
||||
public static HttpHeaders basicAuthHeaders(String username) {
|
||||
return new HttpHeaders() {
|
||||
{
|
||||
String auth = username + ":";
|
||||
byte[] encodedAuth = Base64.encodeBase64(
|
||||
auth.getBytes(Charset.forName("US-ASCII")));
|
||||
String authHeader = "Basic " + new String(encodedAuth);
|
||||
set("Authorization", authHeader);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> T doBasicAuthenticatedRequest(RestTemplate restTemplate, String url, HttpMethod httpMethod, Class<T> responseType) {
|
||||
return doBasicAuthenticatedRequest(restTemplate, url, httpMethod, responseType, null);
|
||||
}
|
||||
|
||||
public static <T> T doBasicAuthenticatedRequest(RestTemplate restTemplate, String url, HttpMethod httpMethod, Class<T> responseType, Object requestObject) {
|
||||
HttpEntity httpEntity;
|
||||
if(requestObject!=null) {
|
||||
httpEntity = new HttpEntity(requestObject, BasicAuthUtils.basicAuthHeaders("test_user@mail.com"));
|
||||
} else {
|
||||
httpEntity = new HttpEntity(BasicAuthUtils.basicAuthHeaders("test_user@mail.com"));
|
||||
}
|
||||
|
||||
return restTemplate.exchange(url,
|
||||
httpMethod,
|
||||
httpEntity,
|
||||
responseType).getBody();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile project(":common-customers")
|
||||
compile project(":common")
|
||||
|
||||
compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion"
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts;
|
||||
|
||||
import io.eventuate.Aggregate;
|
||||
|
||||
import io.eventuate.Event;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts;
|
||||
|
||||
import io.eventuate.Aggregate;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class AccountCreditedEvent extends AccountChangedEvent {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts;
|
||||
|
||||
import io.eventuate.Aggregate;
|
||||
|
||||
import io.eventuate.Event;
|
||||
|
||||
public class AccountDebitFailedDueToInsufficientFundsEvent implements Event {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts;
|
||||
|
||||
import io.eventuate.Aggregate;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class AccountDebitedEvent extends AccountChangedEvent {
|
||||
|
||||
@@ -7,20 +7,20 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAc
|
||||
*/
|
||||
public class CustomerAddedToAccount extends CustomerEvent {
|
||||
|
||||
private ToAccountInfo toAccountInfo;
|
||||
private ToAccountInfo toAccountInfo;
|
||||
|
||||
public CustomerAddedToAccount() {
|
||||
}
|
||||
public CustomerAddedToAccount() {
|
||||
}
|
||||
|
||||
public CustomerAddedToAccount(ToAccountInfo toAccountInfo) {
|
||||
this.toAccountInfo = toAccountInfo;
|
||||
}
|
||||
public CustomerAddedToAccount(ToAccountInfo toAccountInfo) {
|
||||
this.toAccountInfo = toAccountInfo;
|
||||
}
|
||||
|
||||
public ToAccountInfo getToAccountInfo() {
|
||||
return toAccountInfo;
|
||||
}
|
||||
public ToAccountInfo getToAccountInfo() {
|
||||
return toAccountInfo;
|
||||
}
|
||||
|
||||
public void setToAccountInfo(ToAccountInfo toAccountInfo) {
|
||||
this.toAccountInfo = toAccountInfo;
|
||||
}
|
||||
public void setToAccountInfo(ToAccountInfo toAccountInfo) {
|
||||
this.toAccountInfo = toAccountInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,20 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Cust
|
||||
*/
|
||||
public class CustomerCreatedEvent extends CustomerEvent {
|
||||
|
||||
private CustomerInfo customerInfo;
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
public CustomerCreatedEvent() {
|
||||
}
|
||||
public CustomerCreatedEvent() {
|
||||
}
|
||||
|
||||
public CustomerCreatedEvent(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
public CustomerCreatedEvent(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
|
||||
public void setCustomerInfo(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
public void setCustomerInfo(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@ import io.eventuate.EventEntity;
|
||||
/**
|
||||
* Created by Main on 11.02.2016.
|
||||
*/
|
||||
@EventEntity(entity="net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.customers.Customer")
|
||||
public abstract class CustomerEvent implements Event {
|
||||
@EventEntity(entity = "net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.customers.Customer")
|
||||
public abstract class CustomerEvent implements Event {
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class AccountOpenEventSerializationTest {
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 24.03.16.
|
||||
*/
|
||||
public class AddToAccountResponse {
|
||||
|
||||
private String version;
|
||||
|
||||
public AddToAccountResponse() {
|
||||
}
|
||||
|
||||
public AddToAccountResponse(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class Address {
|
||||
@NotNull
|
||||
private String street1;
|
||||
private String street2;
|
||||
@NotNull
|
||||
private String city;
|
||||
@NotNull
|
||||
private String state;
|
||||
@NotNull
|
||||
private String zipCode;
|
||||
|
||||
public Address() {
|
||||
}
|
||||
|
||||
public Address(String street1, String street2, String city, String state, String zipCode) {
|
||||
this.street1 = street1;
|
||||
this.street2 = street2;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getStreet1() {
|
||||
return street1;
|
||||
}
|
||||
|
||||
public void setStreet1(String street1) {
|
||||
this.street1 = street1;
|
||||
}
|
||||
|
||||
public String getStreet2() {
|
||||
return street2;
|
||||
}
|
||||
|
||||
public void setStreet2(String street2) {
|
||||
this.street2 = street2;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
public void setZipCode(String zipCode) {
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
public class CustomerInfo {
|
||||
private Name name;
|
||||
@NotNull
|
||||
protected String email;
|
||||
@NotNull
|
||||
protected String ssn;
|
||||
@NotNull
|
||||
protected String phoneNumber;
|
||||
protected Address address;
|
||||
|
||||
public CustomerInfo() {
|
||||
}
|
||||
|
||||
public CustomerInfo(Name name, String email, String ssn, String phoneNumber, Address address) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.ssn = ssn;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Name getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getSsn() {
|
||||
return ssn;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
public class CustomerResponse {
|
||||
|
||||
private String id;
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
public CustomerResponse() {
|
||||
}
|
||||
|
||||
public CustomerResponse(String id, CustomerInfo customerInfo) {
|
||||
this.id = id;
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
|
||||
public void setCustomerInfo(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by Main on 10.02.2016.
|
||||
*/
|
||||
public class Name {
|
||||
@NotNull
|
||||
private String firstName;
|
||||
@NotNull
|
||||
private String lastName;
|
||||
|
||||
public Name() {
|
||||
}
|
||||
|
||||
public Name(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Main on 05.02.2016.
|
||||
*/
|
||||
public class QuerySideCustomer{
|
||||
private String id;
|
||||
private Name name;
|
||||
private String email;
|
||||
private String ssn;
|
||||
private String phoneNumber;
|
||||
private Address address;
|
||||
private Map<String, ToAccountInfo> toAccounts;
|
||||
|
||||
public QuerySideCustomer() {
|
||||
}
|
||||
|
||||
public QuerySideCustomer(String id, Name name, String email, String ssn, String phoneNumber, Address address, Map<String, ToAccountInfo> toAccounts) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.ssn = ssn;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.address = address;
|
||||
this.toAccounts = toAccounts;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Name getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(Name name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getSsn() {
|
||||
return ssn;
|
||||
}
|
||||
|
||||
public void setSsn(String ssn) {
|
||||
this.ssn = ssn;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public void setPhoneNumber(String phoneNumber) {
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Map<String, ToAccountInfo> getToAccounts() {
|
||||
return toAccounts;
|
||||
}
|
||||
|
||||
public void setToAccounts(Map<String, ToAccountInfo> toAccounts) {
|
||||
this.toAccounts = toAccounts;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
/**
|
||||
* Created by Main on 08.02.2016.
|
||||
*/
|
||||
public class ToAccountInfo {
|
||||
private String id;
|
||||
private String title;
|
||||
private String owner;
|
||||
private String description;
|
||||
|
||||
public ToAccountInfo() {
|
||||
}
|
||||
|
||||
public ToAccountInfo(String id, String title, String owner, String description) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.owner = owner;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile "commons-lang:commons-lang:2.6"
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion"
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class AccountChangeInfo {
|
||||
|
||||
private String changeId;
|
||||
private String transactionId;
|
||||
private String transactionType;
|
||||
private long amount;
|
||||
private long balanceDelta;
|
||||
|
||||
public AccountChangeInfo() {
|
||||
}
|
||||
|
||||
public AccountChangeInfo(String changeId, String transactionId, String transactionType, long amount, long balanceDelta) {
|
||||
this(new Date(), changeId, transactionId, transactionType, amount, balanceDelta);
|
||||
}
|
||||
|
||||
public AccountChangeInfo(Date date, String changeId, String transactionId, String transactionType, long amount, long balanceDelta) {
|
||||
this.changeId = changeId;
|
||||
this.transactionId = transactionId;
|
||||
this.transactionType = transactionType;
|
||||
this.amount = amount;
|
||||
this.balanceDelta = balanceDelta;
|
||||
}
|
||||
|
||||
public String getChangeId() {
|
||||
return changeId;
|
||||
}
|
||||
|
||||
public void setChangeId(String changeId) {
|
||||
this.changeId = changeId;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(String transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public String getTransactionType() {
|
||||
return transactionType;
|
||||
}
|
||||
|
||||
public void setTransactionType(String transactionType) {
|
||||
this.transactionType = transactionType;
|
||||
}
|
||||
|
||||
public long getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(long amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public long getBalanceDelta() {
|
||||
return balanceDelta;
|
||||
}
|
||||
|
||||
public void setBalanceDelta(long balanceDelta) {
|
||||
this.balanceDelta = balanceDelta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 9/1/16.
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
property = "entryType")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = AccountTransactionInfo.class, name = "transaction"),
|
||||
@JsonSubTypes.Type(value = AccountOpenInfo.class, name = "account")
|
||||
})
|
||||
public class AccountHistoryEntry {
|
||||
|
||||
protected Date date;
|
||||
protected EntryType entryType;
|
||||
|
||||
public AccountHistoryEntry() {
|
||||
}
|
||||
|
||||
public AccountHistoryEntry(Date date, EntryType entryType) {
|
||||
this.date = date;
|
||||
this.entryType = entryType;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public EntryType getEntryType() {
|
||||
return entryType;
|
||||
}
|
||||
|
||||
public void setEntryType(EntryType entryType) {
|
||||
this.entryType = entryType;
|
||||
}
|
||||
|
||||
public enum EntryType {
|
||||
transaction, account
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 9/1/16.
|
||||
*/
|
||||
public class AccountHistoryResponse {
|
||||
private List<AccountHistoryEntry> transactionsHistory;
|
||||
|
||||
public AccountHistoryResponse() {
|
||||
}
|
||||
|
||||
public AccountHistoryResponse(List<AccountHistoryEntry> transactionsHistory) {
|
||||
|
||||
this.transactionsHistory = transactionsHistory;
|
||||
}
|
||||
|
||||
public List<AccountHistoryEntry> getTransactionsHistory() {
|
||||
return transactionsHistory;
|
||||
}
|
||||
|
||||
public void setTransactionsHistory(List<AccountHistoryEntry> transactionsHistory) {
|
||||
this.transactionsHistory = transactionsHistory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 9/1/16.
|
||||
*/
|
||||
public class AccountOpenInfo extends AccountHistoryEntry {
|
||||
|
||||
private long initialBalance;
|
||||
|
||||
public AccountOpenInfo() {
|
||||
}
|
||||
|
||||
public AccountOpenInfo(Date date, EntryType entryType, long initialBalance) {
|
||||
super(date, entryType);
|
||||
this.initialBalance=initialBalance;
|
||||
}
|
||||
|
||||
public long getInitialBalance() {
|
||||
return initialBalance;
|
||||
}
|
||||
|
||||
public void setInitialBalance(long initialBalance) {
|
||||
this.initialBalance = initialBalance;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,26 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class AccountTransactionInfo {
|
||||
public class AccountTransactionInfo extends AccountHistoryEntry{
|
||||
|
||||
private String transactionId;
|
||||
private String fromAccountId;
|
||||
private String toAccountId;
|
||||
private long amount;
|
||||
private Date date;
|
||||
private String description;
|
||||
private TransferState status = TransferState.INITIAL;
|
||||
|
||||
public AccountTransactionInfo() {
|
||||
}
|
||||
|
||||
public AccountTransactionInfo(String transactionId, String fromAccountId, String toAccountId, long amount) {
|
||||
this(transactionId, fromAccountId, toAccountId, amount, new Date(), "");
|
||||
this(transactionId, fromAccountId, toAccountId, amount, new Date(), "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,6 +36,7 @@ public class AccountTransactionInfo {
|
||||
this.amount = amount;
|
||||
this.date = date;
|
||||
this.description = description;
|
||||
this.entryType = EntryType.transaction;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
@@ -69,14 +71,6 @@ public class AccountTransactionInfo {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
@@ -85,6 +79,14 @@ public class AccountTransactionInfo {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public TransferState getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(TransferState status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
@@ -1,8 +1,7 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts;
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.DecimalMin;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CreateAccountRequest {
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts;
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
|
||||
public class CreateAccountResponse {
|
||||
@@ -0,0 +1,53 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
public class GetAccountResponse {
|
||||
private String accountId;
|
||||
private BigDecimal balance;
|
||||
private String title;
|
||||
private String description;
|
||||
|
||||
public GetAccountResponse() {
|
||||
}
|
||||
|
||||
public GetAccountResponse(String accountId, BigDecimal balance, String title, String description) {
|
||||
this.accountId = accountId;
|
||||
this.balance = balance;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 9/1/16.
|
||||
*/
|
||||
public class GetAccountsResponse {
|
||||
private List<GetAccountResponse> accounts;
|
||||
|
||||
public GetAccountsResponse() {
|
||||
}
|
||||
|
||||
public GetAccountsResponse(List<GetAccountResponse> accounts) {
|
||||
this.accounts = accounts;
|
||||
}
|
||||
|
||||
public List<GetAccountResponse> getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public void setAccounts(List<GetAccountResponse> accounts) {
|
||||
this.accounts = accounts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 24.03.16.
|
||||
*/
|
||||
public class AddToAccountResponse {
|
||||
|
||||
private String version;
|
||||
|
||||
public AddToAccountResponse() {
|
||||
}
|
||||
|
||||
public AddToAccountResponse(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class Address {
|
||||
@NotNull
|
||||
private String street1;
|
||||
private String street2;
|
||||
@NotNull
|
||||
private String city;
|
||||
@NotNull
|
||||
private String state;
|
||||
@NotNull
|
||||
private String zipCode;
|
||||
|
||||
public Address() {
|
||||
}
|
||||
|
||||
public Address(String street1, String street2, String city, String state, String zipCode) {
|
||||
this.street1 = street1;
|
||||
this.street2 = street2;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getStreet1() {
|
||||
return street1;
|
||||
}
|
||||
|
||||
public void setStreet1(String street1) {
|
||||
this.street1 = street1;
|
||||
}
|
||||
|
||||
public String getStreet2() {
|
||||
return street2;
|
||||
}
|
||||
|
||||
public void setStreet2(String street2) {
|
||||
this.street2 = street2;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
public void setZipCode(String zipCode) {
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
public class CustomerInfo {
|
||||
private Name name;
|
||||
@NotNull
|
||||
protected String email;
|
||||
@NotNull
|
||||
protected String ssn;
|
||||
@NotNull
|
||||
protected String phoneNumber;
|
||||
protected Address address;
|
||||
|
||||
public CustomerInfo() {
|
||||
}
|
||||
|
||||
public CustomerInfo(Name name, String email, String ssn, String phoneNumber, Address address) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.ssn = ssn;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Name getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getSsn() {
|
||||
return ssn;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
public class CustomerResponse {
|
||||
|
||||
private String id;
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
public CustomerResponse() {
|
||||
}
|
||||
|
||||
public CustomerResponse(String id, CustomerInfo customerInfo) {
|
||||
this.id = id;
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
|
||||
public void setCustomerInfo(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by Main on 10.02.2016.
|
||||
*/
|
||||
public class Name {
|
||||
@NotNull
|
||||
private String firstName;
|
||||
@NotNull
|
||||
private String lastName;
|
||||
|
||||
public Name() {
|
||||
}
|
||||
|
||||
public Name(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Main on 05.02.2016.
|
||||
*/
|
||||
public class QuerySideCustomer {
|
||||
private String id;
|
||||
private Name name;
|
||||
private String email;
|
||||
private String ssn;
|
||||
private String phoneNumber;
|
||||
private Address address;
|
||||
private Map<String, ToAccountInfo> toAccounts;
|
||||
|
||||
public QuerySideCustomer() {
|
||||
}
|
||||
|
||||
public QuerySideCustomer(String id, Name name, String email, String ssn, String phoneNumber, Address address, Map<String, ToAccountInfo> toAccounts) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.ssn = ssn;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.address = address;
|
||||
this.toAccounts = toAccounts;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Name getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(Name name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getSsn() {
|
||||
return ssn;
|
||||
}
|
||||
|
||||
public void setSsn(String ssn) {
|
||||
this.ssn = ssn;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public void setPhoneNumber(String phoneNumber) {
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Map<String, ToAccountInfo> getToAccounts() {
|
||||
return toAccounts;
|
||||
}
|
||||
|
||||
public void setToAccounts(Map<String, ToAccountInfo> toAccounts) {
|
||||
this.toAccounts = toAccounts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
/**
|
||||
* Created by Main on 08.02.2016.
|
||||
*/
|
||||
public class ToAccountInfo {
|
||||
private String id;
|
||||
private String title;
|
||||
private String owner;
|
||||
private String description;
|
||||
|
||||
public ToAccountInfo() {
|
||||
}
|
||||
|
||||
public ToAccountInfo(String id, String title, String owner, String description) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.owner = owner;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions;
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.transactions;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.DecimalMin;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CreateMoneyTransferRequest {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions;
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.transactions;
|
||||
|
||||
|
||||
public class CreateMoneyTransferResponse {
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions;
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.transactions;
|
||||
|
||||
public enum TransferState {
|
||||
NEW, INITIAL, DEBITED, COMPLETED, FAILED_DUE_TO_INSUFFICIENT_FUNDS
|
||||
@@ -1,11 +1,11 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile project(":common-customers")
|
||||
compile project(":common")
|
||||
compile project(":common-backend")
|
||||
compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion"
|
||||
|
||||
testCompile project(":testutil-customers")
|
||||
testCompile project(":testutil")
|
||||
testCompile "junit:junit:4.11"
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"
|
||||
|
||||
@@ -7,13 +7,13 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAc
|
||||
*/
|
||||
public class AddToAccountCommand implements CustomerCommand {
|
||||
|
||||
private ToAccountInfo toAccountInfo;
|
||||
private ToAccountInfo toAccountInfo;
|
||||
|
||||
public AddToAccountCommand(ToAccountInfo toAccountInfo) {
|
||||
this.toAccountInfo = toAccountInfo;
|
||||
}
|
||||
public AddToAccountCommand(ToAccountInfo toAccountInfo) {
|
||||
this.toAccountInfo = toAccountInfo;
|
||||
}
|
||||
|
||||
public ToAccountInfo getToAccountInfo() {
|
||||
return toAccountInfo;
|
||||
}
|
||||
public ToAccountInfo getToAccountInfo() {
|
||||
return toAccountInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Cust
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class CreateCustomerCommand implements CustomerCommand {
|
||||
private CustomerInfo customerInfo;
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
public CreateCustomerCommand(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
public CreateCustomerCommand(CustomerInfo customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
}
|
||||
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,24 +14,24 @@ import java.util.List;
|
||||
*/
|
||||
public class Customer extends ReflectiveMutableCommandProcessingAggregate<Customer, CustomerCommand> {
|
||||
|
||||
private CustomerInfo customerInfo;
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
public List<Event> process(CreateCustomerCommand cmd) {
|
||||
return EventUtil.events(new CustomerCreatedEvent(cmd.getCustomerInfo()));
|
||||
}
|
||||
public List<Event> process(CreateCustomerCommand cmd) {
|
||||
return EventUtil.events(new CustomerCreatedEvent(cmd.getCustomerInfo()));
|
||||
}
|
||||
|
||||
public List<Event> process(AddToAccountCommand cmd) {
|
||||
return EventUtil.events(new CustomerAddedToAccount(cmd.getToAccountInfo()));
|
||||
}
|
||||
public List<Event> process(AddToAccountCommand cmd) {
|
||||
return EventUtil.events(new CustomerAddedToAccount(cmd.getToAccountInfo()));
|
||||
}
|
||||
|
||||
public void apply(CustomerCreatedEvent event) {
|
||||
customerInfo = event.getCustomerInfo();
|
||||
}
|
||||
public void apply(CustomerCreatedEvent event) {
|
||||
customerInfo = event.getCustomerInfo();
|
||||
}
|
||||
|
||||
public void apply(CustomerAddedToAccount event) {
|
||||
}
|
||||
public void apply(CustomerAddedToAccount event) {
|
||||
}
|
||||
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import io.eventuate.AggregateRepository;
|
||||
import io.eventuate.EventuateAggregateStore;
|
||||
import io.eventuate.javaclient.spring.EnableEventHandlers;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableEventHandlers
|
||||
@ComponentScan
|
||||
public class CustomerConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -8,22 +8,24 @@ import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateCustomerInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateCustomerInfo;
|
||||
|
||||
public class CustomerTest {
|
||||
|
||||
@Test
|
||||
public void testSomething() {
|
||||
Customer customer = new Customer();
|
||||
@Test
|
||||
public void testSomething() {
|
||||
Customer customer = new Customer();
|
||||
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
|
||||
List<Event> events = customer.process(new CreateCustomerCommand(customerInfo));
|
||||
List<Event> events = customer.process(new CreateCustomerCommand(customerInfo));
|
||||
|
||||
Assert.assertEquals(1, events.size());
|
||||
Assert.assertEquals(CustomerCreatedEvent.class, events.get(0).getClass());
|
||||
|
||||
customer.applyEvent(events.get(0));
|
||||
Assert.assertEquals(customerInfo, customer.getCustomerInfo());
|
||||
}
|
||||
|
||||
Assert.assertEquals(1, events.size());
|
||||
Assert.assertEquals(CustomerCreatedEvent.class, events.get(0).getClass());
|
||||
|
||||
customer.applyEvent(events.get(0));
|
||||
Assert.assertEquals(customerInfo, customer.getCustomerInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ dependencies {
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
||||
|
||||
testCompile project(":testutil-customers")
|
||||
testCompile project(":testutil")
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.custo
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
@@ -15,7 +14,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
|
||||
@Configuration
|
||||
@Import({CustomersCommandSideWebConfiguration.class, EventuateHttpStompClientConfiguration.class, CommonSwaggerConfiguration.class})
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class CustomersCommandSideServiceConfiguration {
|
||||
|
||||
|
||||
@@ -24,6 +22,4 @@ public class CustomersCommandSideServiceConfiguration {
|
||||
HttpMessageConverter<?> additional = new MappingJackson2HttpMessageConverter();
|
||||
return new HttpMessageConverters(additional);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateCustomerInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateCustomerInfo;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = CustomersCommandSideServiceTestConfiguration.class)
|
||||
@@ -25,7 +25,7 @@ public class CustomersCommandSideServiceIntegrationTest {
|
||||
private int port;
|
||||
|
||||
private String baseUrl(String path) {
|
||||
return "http://localhost:" + port + "/" + path;
|
||||
return "http://localhost:" + port + "/api" + path;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import io.eventuate.javaclient.spring.jdbc.EventuateJdbcEventStoreConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.AuthConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonswagger.CommonSwaggerConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.customers.CustomersCommandSideWebConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -13,9 +17,16 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Import({CustomersCommandSideServiceConfiguration.class, AuthConfiguration.class})
|
||||
@Import({CustomersCommandSideWebConfiguration.class, EventuateJdbcEventStoreConfiguration.class, CommonSwaggerConfiguration.class, AuthConfiguration.class})
|
||||
@EnableAutoConfiguration
|
||||
public class CustomersCommandSideServiceTestConfiguration {
|
||||
|
||||
@Bean
|
||||
public HttpMessageConverters customConverters() {
|
||||
HttpMessageConverter<?> additional = new MappingJackson2HttpMessageConverter();
|
||||
return new HttpMessageConverters(additional);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpMessageConverters converters) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile project(":common-customers")
|
||||
compile project(":common")
|
||||
compile project(":customers-command-side-backend")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
|
||||
@@ -15,26 +15,26 @@ import java.util.concurrent.CompletableFuture;
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/customers")
|
||||
@RequestMapping("/api/customers")
|
||||
public class CustomerController {
|
||||
|
||||
private CustomerService customerService;
|
||||
private CustomerService customerService;
|
||||
|
||||
@Autowired
|
||||
public CustomerController(CustomerService customerService) {
|
||||
this.customerService = customerService;
|
||||
}
|
||||
@Autowired
|
||||
public CustomerController(CustomerService customerService) {
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public CompletableFuture<CustomerResponse> createCustomer(@Validated @RequestBody CustomerInfo customer) {
|
||||
return customerService.createCustomer(customer)
|
||||
.thenApply(entityAndEventInfo -> new CustomerResponse(entityAndEventInfo.getEntityId(), customer));
|
||||
}
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public CompletableFuture<CustomerResponse> createCustomer(@Validated @RequestBody CustomerInfo customer) {
|
||||
return customerService.createCustomer(customer)
|
||||
.thenApply(entityAndEventInfo -> new CustomerResponse(entityAndEventInfo.getEntityId(), customer));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}/toaccounts", method = RequestMethod.POST)
|
||||
public CompletableFuture<AddToAccountResponse> addToAccount(@PathVariable String id, @Validated @RequestBody ToAccountInfo request) {
|
||||
return customerService.addToAccount(id, request)
|
||||
.thenApply(entityAndEventInfo -> new AddToAccountResponse(entityAndEventInfo.getEntityVersion().toString()));
|
||||
}
|
||||
@RequestMapping(value = "/{id}/toaccounts", method = RequestMethod.POST)
|
||||
public CompletableFuture<AddToAccountResponse> addToAccount(@PathVariable String id, @Validated @RequestBody ToAccountInfo request) {
|
||||
return customerService.addToAccount(id, request)
|
||||
.thenApply(entityAndEventInfo -> new AddToAccountResponse(entityAndEventInfo.getEntityVersion().toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class CustomerQueryService {
|
||||
return CompletableFuture.completedFuture(customer);
|
||||
}
|
||||
|
||||
public CompletableFuture<List<QuerySideCustomer>> findByEmail(String email){
|
||||
public CompletableFuture<List<QuerySideCustomer>> findByEmail(String email) {
|
||||
List<QuerySideCustomer> customers = querySideCustomerRepository.findByEmailLike(email);
|
||||
if (customers.isEmpty())
|
||||
return CompletableFutureUtil.failedFuture(new EmptyResultDataAccessException(1));
|
||||
|
||||
@@ -15,31 +15,31 @@ import org.slf4j.LoggerFactory;
|
||||
@EventSubscriber(id = "customerQuerySideEventHandlers")
|
||||
public class CustomerQueryWorkflow {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private CustomerInfoUpdateService customerInfoUpdateService;
|
||||
private CustomerInfoUpdateService customerInfoUpdateService;
|
||||
|
||||
|
||||
public CustomerQueryWorkflow(CustomerInfoUpdateService customerInfoUpdateService) {
|
||||
this.customerInfoUpdateService = customerInfoUpdateService;
|
||||
}
|
||||
public CustomerQueryWorkflow(CustomerInfoUpdateService customerInfoUpdateService) {
|
||||
this.customerInfoUpdateService = customerInfoUpdateService;
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void create(DispatchedEvent<CustomerCreatedEvent> de) {
|
||||
CustomerCreatedEvent event = de.getEvent();
|
||||
String id = de.getEntityId();
|
||||
@EventHandlerMethod
|
||||
public void create(DispatchedEvent<CustomerCreatedEvent> de) {
|
||||
CustomerCreatedEvent event = de.getEvent();
|
||||
String id = de.getEntityId();
|
||||
|
||||
customerInfoUpdateService.create(id, event.getCustomerInfo());
|
||||
}
|
||||
customerInfoUpdateService.create(id, event.getCustomerInfo());
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void addToAccount(DispatchedEvent<CustomerAddedToAccount> de) {
|
||||
CustomerAddedToAccount event = de.getEvent();
|
||||
String id = de.getEntityId();
|
||||
@EventHandlerMethod
|
||||
public void addToAccount(DispatchedEvent<CustomerAddedToAccount> de) {
|
||||
CustomerAddedToAccount event = de.getEvent();
|
||||
String id = de.getEntityId();
|
||||
|
||||
ToAccountInfo toAccountInfo = event.getToAccountInfo();
|
||||
ToAccountInfo toAccountInfo = event.getToAccountInfo();
|
||||
|
||||
customerInfoUpdateService.addToAccount(id, toAccountInfo);
|
||||
}
|
||||
customerInfoUpdateService.addToAccount(id, toAccountInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.cu
|
||||
|
||||
import io.eventuate.javaclient.spring.EnableEventHandlers;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
@@ -12,26 +13,27 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
|
||||
@Configuration
|
||||
@EnableMongoRepositories
|
||||
@EnableEventHandlers
|
||||
@ComponentScan
|
||||
public class QuerySideCustomerConfiguration {
|
||||
@Bean
|
||||
public CustomerQueryWorkflow customerQueryWorkflow(CustomerInfoUpdateService accountInfoUpdateService) {
|
||||
return new CustomerQueryWorkflow(accountInfoUpdateService);
|
||||
}
|
||||
@Bean
|
||||
public CustomerQueryWorkflow customerQueryWorkflow(CustomerInfoUpdateService accountInfoUpdateService) {
|
||||
return new CustomerQueryWorkflow(accountInfoUpdateService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomerInfoUpdateService customerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
|
||||
return new CustomerInfoUpdateService(querySideCustomerRepository);
|
||||
}
|
||||
@Bean
|
||||
public CustomerInfoUpdateService customerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
|
||||
return new CustomerInfoUpdateService(querySideCustomerRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomerQueryService customerQueryService(QuerySideCustomerRepository accountInfoRepository) {
|
||||
return new CustomerQueryService(accountInfoRepository);
|
||||
}
|
||||
@Bean
|
||||
public CustomerQueryService customerQueryService(QuerySideCustomerRepository accountInfoRepository) {
|
||||
return new CustomerQueryService(accountInfoRepository);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public QuerySideDependencyChecker querysideDependencyChecker(MongoTemplate mongoTemplate) {
|
||||
return new QuerySideDependencyChecker(mongoTemplate);
|
||||
}
|
||||
@Bean
|
||||
public QuerySideDependencyChecker querysideDependencyChecker(MongoTemplate mongoTemplate) {
|
||||
return new QuerySideDependencyChecker(mongoTemplate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ import java.util.List;
|
||||
|
||||
interface QuerySideCustomerRepository extends MongoRepository<QuerySideCustomer, String> {
|
||||
|
||||
List<QuerySideCustomer> findByEmailLike(String email);
|
||||
List<QuerySideCustomer> findByEmailLike(String email);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user