- completed moving "toAccounts" from List to Map

- created CustomerEvent superclass
- removed redundant CustomersNotFoundException
- added integration tests for customers
This commit is contained in:
Main
2016-02-11 21:47:48 +03:00
parent c0a9d6ed7d
commit 5c85418cc4
21 changed files with 131 additions and 63 deletions

View File

@@ -19,7 +19,7 @@ import java.math.BigDecimal;
import static net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.MoneyUtil.toIntegerRepr;
@EventSubscriber(id="querySideEventHandlers")
@EventSubscriber(id="accountQuerySideEventHandlers")
public class AccountQueryWorkflow implements CompoundEventHandler {
private Logger logger = LoggerFactory.getLogger(getClass());

View File

@@ -8,6 +8,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.acc
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Address;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Name;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
import org.junit.Assert;
@@ -40,11 +41,13 @@ public class CustomerQuerySideIntegrationTest {
private EventStore eventStore;
@Test
public void shouldCreateCustomer() throws Exception {
public void shouldCreateCustomerAndAddToAccount() throws Exception {
CustomerInfo customerInfo = generateCustomerInfo();
EntityWithIdAndVersion<Customer> customer = await(customerService.createCustomer(customerInfo));
Thread.sleep(10000);
ToAccountInfo toAccountInfo = generateToAccountInfo();
EntityWithIdAndVersion<Customer> customerWithNewAccount = await(customerService.addToAccount(customer.getEntityIdentifier().getId(), toAccountInfo));
eventually(
new Producer<QuerySideCustomer>() {
@Override
@@ -60,6 +63,10 @@ public class CustomerQuerySideIntegrationTest {
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);
}
});
}
@@ -77,4 +84,8 @@ public class CustomerQuerySideIntegrationTest {
"1111111")
);
}
private ToAccountInfo generateToAccountInfo() {
return new ToAccountInfo("11111111-11111111", "New Account", "John Doe");
}
}

View File

@@ -1,19 +1,18 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers;
import net.chrisrichardson.eventstore.Event;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
/**
* Created by Main on 08.02.2016.
*/
public class CustomerAddedToAccount implements Event {
public class CustomerAddedToAccount extends CustomerEvent {
private ToAccountInfo toAccountInfo;
public CustomerAddedToAccount() {
}
public CustomerAddedToAccount( ToAccountInfo toAccountInfo) {
public CustomerAddedToAccount(ToAccountInfo toAccountInfo) {
this.toAccountInfo = toAccountInfo;
}

View File

@@ -1,13 +1,11 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers;
import net.chrisrichardson.eventstore.Event;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Name;
/**
* Created by popikyardo on 02.02.16.
*/
public class CustomerCreatedEvent implements Event {
public class CustomerCreatedEvent extends CustomerEvent {
private CustomerInfo customerInfo;

View File

@@ -0,0 +1,11 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers;
import net.chrisrichardson.eventstore.Event;
import net.chrisrichardson.eventstore.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 {
}

View File

@@ -1,2 +0,0 @@
@net.chrisrichardson.eventstore.EventEntity(entity="net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.customers.Customer")
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers;

View File

@@ -1,6 +1,9 @@
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.
*/
@@ -9,6 +12,9 @@ public class ToAccountInfo {
private String title;
private String owner;
public ToAccountInfo() {
}
public ToAccountInfo(String id, String title, String owner) {
this.id = id;
this.title = title;
@@ -19,11 +25,33 @@ public class ToAccountInfo {
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;
}
@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}

View File

@@ -2,7 +2,7 @@ package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.client.config.EventStoreHttpClientConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.commonswagger.CommonSwaggerConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.customers.CommandSideWebCustomersConfiguration;
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;
@@ -13,7 +13,7 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration
@Import({CommandSideWebCustomersConfiguration.class, EventStoreHttpClientConfiguration.class, CommonSwaggerConfiguration.class})
@Import({CustomersCommandSideWebConfiguration.class, EventStoreHttpClientConfiguration.class, CommonSwaggerConfiguration.class})
@EnableAutoConfiguration
@ComponentScan
public class CustomersCommandSideServiceConfiguration {

View File

@@ -19,7 +19,7 @@ import java.util.List;
@Configuration
@Import({CustomerConfiguration.class})
@ComponentScan
public class CommandSideWebCustomersConfiguration extends WebMvcConfigurerAdapter {
public class CustomersCommandSideWebConfiguration extends WebMvcConfigurerAdapter {
class FakeThing {}

View File

@@ -4,14 +4,9 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Cust
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import java.util.Collections;
import static org.springframework.data.mongodb.core.query.Criteria.where;
/**
* Created by Main on 04.02.2016.
*/
@@ -20,11 +15,9 @@ public class CustomerInfoUpdateService {
private Logger logger = LoggerFactory.getLogger(getClass());
private QuerySideCustomerRepository accountInfoRepository;
private MongoTemplate mongoTemplate;
public CustomerInfoUpdateService(QuerySideCustomerRepository accountInfoRepository, MongoTemplate mongoTemplate) {
public CustomerInfoUpdateService(QuerySideCustomerRepository accountInfoRepository) {
this.accountInfoRepository = accountInfoRepository;
this.mongoTemplate = mongoTemplate;
}
public void create(String id, CustomerInfo customerInfo) {
@@ -35,7 +28,7 @@ public class CustomerInfoUpdateService {
customerInfo.getSsn(),
customerInfo.getPhoneNumber(),
customerInfo.getAddress(),
Collections.<ToAccountInfo>emptyList()
Collections.<String, ToAccountInfo>emptyMap()
)
);
logger.info("Saved in mongo");
@@ -46,10 +39,9 @@ public class CustomerInfoUpdateService {
}
public void addToAccount(String id, ToAccountInfo accountInfo) {
mongoTemplate.updateMulti(new Query(where("id").is(id)),
new Update().
push("toAccounts", accountInfo),
QuerySideCustomer.class);
QuerySideCustomer customer = accountInfoRepository.findOne(id);
customer.getToAccounts().put(accountInfo.getId(), accountInfo);
accountInfoRepository.save(customer);
}
}

View File

@@ -1,8 +0,0 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers;
public class CustomerNotFoundException extends RuntimeException {
public CustomerNotFoundException(String customerId) {
super("Customer not found " + customerId);
}
}

View File

@@ -1,6 +1,7 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers;
import net.chrisrichardson.eventstore.EntityIdentifier;
import org.springframework.dao.EmptyResultDataAccessException;
import rx.Observable;
import java.util.List;
@@ -16,7 +17,7 @@ public class CustomerQueryService {
public Observable<QuerySideCustomer> findByCustomerId(EntityIdentifier customerId) {
QuerySideCustomer customer = querySideCustomerRepository.findOne(customerId.getId());
if (customer == null)
return Observable.error(new CustomerNotFoundException(customerId.getId()));
return Observable.error(new EmptyResultDataAccessException(1));
else
return Observable.just(customer);
}
@@ -24,7 +25,7 @@ public class CustomerQueryService {
public Observable<List<QuerySideCustomer>> findByEmail(String email){
List<QuerySideCustomer> customers = querySideCustomerRepository.findByEmailLike(email);
if (customers.isEmpty())
return Observable.error(new CustomersNotFoundException());
return Observable.error(new EmptyResultDataAccessException(1));
else
return Observable.just(customers);
}

View File

@@ -14,7 +14,7 @@ import rx.Observable;
/**
* Created by Main on 04.02.2016.
*/
@EventSubscriber(id = "querySideEventHandlers")
@EventSubscriber(id = "customerQuerySideEventHandlers")
public class CustomerQueryWorkflow implements CompoundEventHandler {
private Logger logger = LoggerFactory.getLogger(getClass());

View File

@@ -1,8 +0,0 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers;
public class CustomersNotFoundException extends RuntimeException {
public CustomersNotFoundException() {
super("Customers not found");
}
}

View File

@@ -5,16 +5,16 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Cust
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Name;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
import java.util.List;
import java.util.Map;
/**
* Created by Main on 05.02.2016.
*/
public class QuerySideCustomer extends CustomerInfo {
private String id;
private List<ToAccountInfo> toAccounts;
private Map<String, ToAccountInfo> toAccounts;
public QuerySideCustomer(String id, Name name, String email, String ssn, String phoneNumber, Address address, List<ToAccountInfo> toAccounts) {
public QuerySideCustomer(String id, Name name, String email, String ssn, String phoneNumber, Address address, Map<String, ToAccountInfo> toAccounts) {
super(name, email, ssn, phoneNumber, address);
this.id = id;
this.toAccounts = toAccounts;
@@ -24,7 +24,7 @@ public class QuerySideCustomer extends CustomerInfo {
return id;
}
public List<ToAccountInfo> getToAccounts() {
public Map<String, ToAccountInfo> getToAccounts() {
return toAccounts;
}
}

View File

@@ -19,8 +19,8 @@ public class QuerySideCustomerConfiguration {
}
@Bean
public CustomerInfoUpdateService customerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository, MongoTemplate mongoTemplate) {
return new CustomerInfoUpdateService(querySideCustomerRepository, mongoTemplate);
public CustomerInfoUpdateService customerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
return new CustomerInfoUpdateService(querySideCustomerRepository);
}
@Bean

View File

@@ -1,12 +1,11 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.customers;
import net.chrisrichardson.eventstore.EntityIdentifier;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers.CustomerNotFoundException;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers.CustomerQueryService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers.CustomersNotFoundException;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers.QuerySideCustomer;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import rx.Observable;
@@ -39,14 +38,9 @@ public class CustomerQueryController {
.map(this::getCustomersQueryResponse);
}
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "customer not found")
@ExceptionHandler(CustomerNotFoundException.class)
public void customerNotFound() {
}
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "customers not found")
@ExceptionHandler(CustomersNotFoundException.class)
@ExceptionHandler(EmptyResultDataAccessException.class)
public void customersNotFound() {
}

View File

@@ -63,10 +63,10 @@ public class EndToEndTest {
BigDecimal finalFromAccountBalance = initialFromAccountBalance.subtract(amountToTransfer);
BigDecimal finalToAccountBalance = initialToAccountBalance.add(amountToTransfer);
final CreateAccountResponse fromAccount = restTemplate.postForEntity(accountsCommandSideBaseUrl("/accounts"), new CreateAccountRequest("00000000-00000000", "My Account", initialFromAccountBalance), CreateAccountResponse.class).getBody();
final CreateAccountResponse fromAccount = restTemplate.postForEntity(accountsCommandSideBaseUrl("/accounts"), new CreateAccountRequest("00000000-00000000", "My #1 Account", initialFromAccountBalance), CreateAccountResponse.class).getBody();
final String fromAccountId = fromAccount.getAccountId();
CreateAccountResponse toAccount = restTemplate.postForEntity(accountsCommandSideBaseUrl("/accounts"), new CreateAccountRequest("00000000-00000000", "My Account", initialToAccountBalance), CreateAccountResponse.class).getBody();
CreateAccountResponse toAccount = restTemplate.postForEntity(accountsCommandSideBaseUrl("/accounts"), new CreateAccountRequest("00000000-00000000", "My #2 Account", initialToAccountBalance), CreateAccountResponse.class).getBody();
String toAccountId = toAccount.getAccountId();
Assert.assertNotNull(fromAccountId);

View File

@@ -6,6 +6,8 @@ dependencies {
compile project(":accounts-query-side-web")
compile project(":accounts-command-side-web")
compile project(":transactions-command-side-web")
compile project(":customers-command-side-web")
compile project(":customers-query-side-web")
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-actuator"

View File

@@ -1,7 +1,9 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CommandSideWebAccountsConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.customers.CustomersCommandSideWebConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CommandSideWebTransactionsConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.CustomersQuerySideWebConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.QuerySideWebConfiguration;
import net.chrisrichardson.eventstore.jdbc.config.JdbcEventStoreConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -14,7 +16,7 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration
@Import({CommandSideWebAccountsConfiguration.class, CommandSideWebTransactionsConfiguration.class, JdbcEventStoreConfiguration.class, QuerySideWebConfiguration.class})
@Import({CommandSideWebAccountsConfiguration.class, CommandSideWebTransactionsConfiguration.class, JdbcEventStoreConfiguration.class, QuerySideWebConfiguration.class, CustomersQuerySideWebConfiguration.class, CustomersCommandSideWebConfiguration.class})
@EnableAutoConfiguration
@ComponentScan
public class BankingWebConfiguration {

View File

@@ -1,5 +1,6 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.*;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse;
@@ -71,6 +72,19 @@ public class BankingWebIntegrationTest {
}
@Test
public void shouldCreateCustomers() {
CustomerInfo customerInfo = generateCustomerInfo();
final CustomerResponse customerResponse = restTemplate.postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
Assert.assertNotNull(customerId);
Assert.assertEquals(customerInfo, customerResponse.getCustomerInfo());
assertCustomerResponse(customerId, customerInfo);
}
private BigDecimal toCents(BigDecimal dollarAmount) {
return dollarAmount.multiply(new BigDecimal(100));
}
@@ -93,4 +107,38 @@ public class BankingWebIntegrationTest {
});
}
private void assertCustomerResponse(final String customerId, final CustomerInfo customerInfo) {
eventually(
new Producer<CustomerResponse>() {
@Override
public Observable<CustomerResponse> produce() {
return Observable.just(restTemplate.getForEntity(baseUrl("/customers/" + customerId), CustomerResponse.class).getBody());
}
},
new Verifier<CustomerResponse>() {
@Override
public void verify(CustomerResponse customerResponse) {
Assert.assertEquals(customerId, customerResponse.getId());
Assert.assertEquals(customerInfo, customerResponse.getCustomerInfo());
}
});
}
private CustomerInfo generateCustomerInfo() {
return new CustomerInfo(
new Name("John", "Doe"),
"current@email.com",
"000-00-0000",
"1-111-111-1111",
new Address("street 1",
"street 2",
"City",
"State",
"1111111")
);
}
private ToAccountInfo generateToAccountInfo() {
return new ToAccountInfo("11111111-11111111", "New Account", "John Doe");
}
}