Improved module name <functional-area>-<Command|Query>....
Standalone services now use the Event Store Server (many tests still use the embedded server)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -27,3 +27,5 @@ local_developer_config
|
||||
|
||||
|
||||
/web/web.log
|
||||
*.log
|
||||
*.pid
|
||||
|
||||
17
README.md
17
README.md
@@ -4,7 +4,7 @@ This example application is the money transfer application described in my talk
|
||||
This talk describe a way of architecting highly scalable and available applications that is based on microservices, polyglot persistence,
|
||||
event sourcing (ES) and command query responsibility separation (CQRS).
|
||||
Applications consist of loosely coupled components that communicate using events.
|
||||
These components can be deployed either as separate services or, as they are here, packaged as a monolithic application for simplified development and testing.
|
||||
These components can be deployed either as separate services or packaged as a monolithic application for simplified development and testing.
|
||||
|
||||
# About the examples
|
||||
|
||||
@@ -19,12 +19,23 @@ For more information, please see the [wiki](../../wiki)
|
||||
|
||||
# About the event store
|
||||
|
||||
The application use an embedded SQL-based event store.
|
||||
The application use one of two event stores:
|
||||
|
||||
* embedded SQL-based event store, which is great for integration tests
|
||||
* event store server
|
||||
|
||||
# Running the tests
|
||||
|
||||
To run the tests you need to set the following environment variable:
|
||||
To run the tests you need to set some environment variable.
|
||||
|
||||
First, you need to tell the query side code how to connect to MongoDB:
|
||||
|
||||
```
|
||||
export SPRING_DATA_MONGODB_URI=mongodb://192.168.59.103/yourdb
|
||||
```
|
||||
|
||||
Docker is a great way to run MongoDB.
|
||||
For more information please see this [blog post](http://plainoldobjects.com/2015/01/14/need-to-install-mongodb-rabbitmq-or-mysql-use-docker-to-simplify-dev-and-test/).
|
||||
|
||||
Second, in order for the tests in accounts-command-side-service, transactions-command-side-service and accounts-query-side-service to pass you need to set some environment variables that tell the service how to connect to the Event Store server.
|
||||
But don't worry. The build is configured to ignore failures for those projects
|
||||
|
||||
5
es-examples-docker/docker-compose.yml
Normal file
5
es-examples-docker/docker-compose.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
mongodb:
|
||||
image: dockerfile/mongodb
|
||||
ports:
|
||||
- "27017:27017"
|
||||
|
||||
4
es-examples-docker/mongodb-cli.sh
Executable file
4
es-examples-docker/mongodb-cli.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#! /bin/bash
|
||||
|
||||
docker run --link esexamplesdocker_mongodb_1:mongodb -i -t dockerfile/mongodb:latest /usr/bin/mongo --host mongodb
|
||||
|
||||
36
handy-curl-commands.sh
Normal file
36
handy-curl-commands.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#! /bin/bash -e
|
||||
|
||||
|
||||
# Create account 1
|
||||
|
||||
account1=$(curl -v --data '{"initialBalance" : 500}' -H "content-type: application/json" http://localhost:8080/accounts)
|
||||
|
||||
# {"accountId":"0000014ae4caf314-ae7453bbb71e0000"}
|
||||
|
||||
curl -v http://localhost:8081/accounts/0000014ae4caf314-ae7453bbb71e0000
|
||||
|
||||
# {"accountId":"0000014ae4caf314-ae7453bbb71e0000","balance":50000}
|
||||
|
||||
# Create account 2
|
||||
|
||||
account2=$(curl -v --data '{"initialBalance" : 300}' -H "content-type: application/json" http://localhost:8080/accounts)
|
||||
|
||||
# {"accountId":"0000014ae4cc8415-ae7453bbb71e0000"}
|
||||
|
||||
curl -v http://localhost:8081/accounts/0000014ae4cc8415-ae7453bbb71e0000
|
||||
|
||||
#
|
||||
|
||||
|
||||
transfer=$(curl -v --data '{"amount" : 150, "fromAccountId" : "0000014ae4caf314-ae7453bbb71e0000", "toAccountId" : "0000014ae4cc8415-ae7453bbb71e0000"}' -H "content-type: application/json" http://localhost:8082/transfers)
|
||||
|
||||
# {"moneyTransferId":"0000014ae4cef030-ae7453bbb71e0000"}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
This is the Java/Spring version of the Event Sourcing/CQRS money transfer example application.
|
||||
|
||||
# About the application
|
||||
|
||||
This application consists of three microservices:
|
||||
|
||||
* Account Service - the command side business logic for Accounts
|
||||
@@ -8,25 +10,28 @@ This application consists of three microservices:
|
||||
|
||||
The Account Service consists of the following modules:
|
||||
|
||||
* commandside-backend-accounts - the Account aggregate
|
||||
* commandside-web-accounts - a REST API for creating and retrieving Accounts
|
||||
* 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:
|
||||
|
||||
* commandside-backend-transactions - the MoneyTransfer aggregate
|
||||
* commandside-web-transactions - a REST API for creating and retrieving Money Transfers
|
||||
* 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:
|
||||
|
||||
* queryside-backend - MongoDB-based, denormalized view of Accounts and MoneyTransfers
|
||||
* queryside-web - a REST API for querying the denormalized view
|
||||
* accounts-query-side-backend - MongoDB-based, denormalized view of Accounts and MoneyTransfers
|
||||
* accounts-query-side-web - a REST API for querying the denormalized view
|
||||
* accounts-query-side-service - a standalone microservice
|
||||
|
||||
In order to be used with the embedded Event Store, the three services are currently packaged as a single monolithic web application:
|
||||
# Deploying the application
|
||||
|
||||
* monolithic-web - all-in-one, monolithic packaging of 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.
|
||||
|
||||
As well as the above modules there are also:
|
||||
The three services can also be packaged as a single monolithic web application in order to be used with the embedded Event Store:
|
||||
|
||||
* common-backend - code that is shared between the command side and the query side, primarily events and value objects
|
||||
* backend-integration-tests - integrations tests for the backend
|
||||
|
||||
* monolithic-service - all-in-one, monolithic packaging of the application
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts;
|
||||
|
||||
import net.chrisrichardson.eventstore.EventStore;
|
||||
import net.chrisrichardson.eventstore.javaapi.consumer.EnableJavaEventHandlers;
|
||||
import net.chrisrichardson.eventstore.repository.AggregateRepository;
|
||||
import net.chrisrichardson.eventstore.subscriptions.EnableEventHandlers;
|
||||
import net.chrisrichardson.eventstore.subscriptions.EventHandlerRegistrarFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableEventHandlers
|
||||
@EnableJavaEventHandlers
|
||||
public class AccountConfiguration {
|
||||
|
||||
|
||||
@Autowired
|
||||
private EventHandlerRegistrarFactory eventHandlerRegistrarFactory;
|
||||
|
||||
@Bean
|
||||
public AccountWorkflow accountWorkflow() {
|
||||
return new AccountWorkflow();
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts;
|
||||
|
||||
import net.chrisrichardson.eventstore.EntityIdentifier;
|
||||
import net.chrisrichardson.eventstore.javaapi.consumer.EventHandlerContext;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.DebitRecordedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent;
|
||||
import net.chrisrichardson.eventstore.subscriptions.*;
|
||||
21
java-spring/accounts-command-side-service/build.gradle
Normal file
21
java-spring/accounts-command-side-service/build.gradle
Normal file
@@ -0,0 +1,21 @@
|
||||
apply plugin: VerifyMongoDBConfigurationPlugin
|
||||
apply plugin: VerifyEventStoreEnvironmentPlugin
|
||||
|
||||
apply plugin: 'spring-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(":accounts-command-side-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
||||
|
||||
compile "net.chrisrichardson.eventstore.client:eventstore-http-stomp-client:$eventStoreClientVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
ignoreFailures true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import net.chrisrichardson.eventstore.client.config.EventStoreHttpClientConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CommandSideWebAccountsConfiguration;
|
||||
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;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
|
||||
@Configuration
|
||||
@Import({CommandSideWebAccountsConfiguration.class, EventStoreHttpClientConfiguration.class })
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class AccountsCommandSideServiceConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public HttpMessageConverters customConverters() {
|
||||
HttpMessageConverter<?> additional = new MappingJackson2HttpMessageConverter();
|
||||
return new HttpMessageConverters(additional);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.main;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.AccountsCommandSideServiceConfiguration;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
|
||||
public class AccountsCommandSideServiceMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AccountsCommandSideServiceConfiguration.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
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 org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = AccountsCommandSideServiceTestConfiguration.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest({"server.port=0", "management.port=0"})
|
||||
public class AccountsCommandSideServiceIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
private String baseUrl(String path) {
|
||||
return "http://localhost:" + port + "/" + path;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
RestTemplate restTemplate;
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccountsAndTransferMoney() {
|
||||
BigDecimal initialFromAccountBalance = new BigDecimal(500);
|
||||
BigDecimal initialToAccountBalance = new BigDecimal(100);
|
||||
BigDecimal amountToTransfer = new BigDecimal(150);
|
||||
|
||||
final CreateAccountResponse fromAccount = restTemplate.postForEntity(baseUrl("/accounts"), new CreateAccountRequest(initialFromAccountBalance), CreateAccountResponse.class).getBody();
|
||||
final String fromAccountId = fromAccount.getAccountId();
|
||||
|
||||
CreateAccountResponse toAccount = restTemplate.postForEntity(baseUrl("/accounts"), new CreateAccountRequest(initialToAccountBalance), CreateAccountResponse.class).getBody();
|
||||
String toAccountId = toAccount.getAccountId();
|
||||
|
||||
Assert.assertNotNull(fromAccountId);
|
||||
Assert.assertNotNull(toAccountId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Import(AccountsCommandSideServiceConfiguration.class)
|
||||
public class AccountsCommandSideServiceTestConfiguration {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpMessageConverters converters) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
HttpMessageConverter<?> httpMessageConverter = converters.getConverters().get(0);
|
||||
List<? extends HttpMessageConverter<?>> httpMessageConverters = Arrays.asList(new MappingJackson2HttpMessageConverter());
|
||||
restTemplate.setMessageConverters((List<HttpMessageConverter<?>>) httpMessageConverters);
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(":commandside-backend-accounts")
|
||||
compile project(":web-common")
|
||||
compile project(":accounts-command-side-backend")
|
||||
compile project(":common-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
|
||||
|
||||
|
||||
import net.chrisrichardson.eventstore.subscriptions.EnableEventHandlers;
|
||||
import net.chrisrichardson.eventstore.javaapi.consumer.EnableJavaEventHandlers;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
@@ -9,7 +9,7 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
|
||||
|
||||
@Configuration
|
||||
@EnableMongoRepositories
|
||||
@EnableEventHandlers
|
||||
@EnableJavaEventHandlers
|
||||
public class QuerySideAccountConfiguration {
|
||||
|
||||
@Bean
|
||||
20
java-spring/accounts-query-side-service/build.gradle
Normal file
20
java-spring/accounts-query-side-service/build.gradle
Normal file
@@ -0,0 +1,20 @@
|
||||
apply plugin: VerifyMongoDBConfigurationPlugin
|
||||
apply plugin: VerifyEventStoreEnvironmentPlugin
|
||||
|
||||
apply plugin: 'spring-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(":accounts-query-side-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
||||
|
||||
compile "net.chrisrichardson.eventstore.client:eventstore-http-stomp-client:$eventStoreClientVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
ignoreFailures true
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import net.chrisrichardson.eventstore.client.config.EventStoreHttpClientConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.QuerySideWebConfiguration;
|
||||
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;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
|
||||
@Configuration
|
||||
@Import({QuerySideWebConfiguration.class, EventStoreHttpClientConfiguration.class})
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class AccountsQuerySideServiceConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public HttpMessageConverters customConverters() {
|
||||
HttpMessageConverter<?> additional = new MappingJackson2HttpMessageConverter();
|
||||
return new HttpMessageConverters(additional);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.main;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.AccountsQuerySideServiceConfiguration;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
|
||||
public class AccountsQuerySideServiceMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AccountsQuerySideServiceConfiguration.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
|
||||
import rx.Observable;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = AccountsQuerySideServiceTestConfiguration.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest({"server.port=0", "management.port=0"})
|
||||
public class AccountsQuerySideServiceIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
private String baseUrl(String path) {
|
||||
return "http://localhost:" + port + "/" + path;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
RestTemplate restTemplate;
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccountsAndTransferMoney() {
|
||||
// TBD
|
||||
}
|
||||
|
||||
private BigDecimal toCents(BigDecimal dollarAmount) {
|
||||
return dollarAmount.multiply(new BigDecimal(100));
|
||||
}
|
||||
|
||||
private void assertAccountBalance(final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
|
||||
final BigDecimal inCents = toCents(expectedBalanceInDollars);
|
||||
eventually(
|
||||
new Producer<GetAccountResponse>() {
|
||||
@Override
|
||||
public Observable<GetAccountResponse> produce() {
|
||||
return Observable.just(restTemplate.getForEntity(baseUrl("/accounts/" + fromAccountId), GetAccountResponse.class).getBody());
|
||||
}
|
||||
},
|
||||
new Verifier<GetAccountResponse>() {
|
||||
@Override
|
||||
public void verify(GetAccountResponse accountInfo) {
|
||||
Assert.assertEquals(fromAccountId, accountInfo.getAccountId());
|
||||
Assert.assertEquals(inCents, accountInfo.getBalance());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Import(AccountsQuerySideServiceConfiguration.class)
|
||||
public class AccountsQuerySideServiceTestConfiguration {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpMessageConverters converters) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
HttpMessageConverter<?> httpMessageConverter = converters.getConverters().get(0);
|
||||
List<? extends HttpMessageConverter<?>> httpMessageConverters = Arrays.asList(new MappingJackson2HttpMessageConverter());
|
||||
restTemplate.setMessageConverters((List<HttpMessageConverter<?>>) httpMessageConverters);
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(":queryside-backend")
|
||||
compile project(":web-common")
|
||||
compile project(":accounts-query-side-backend")
|
||||
compile project(":common-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
||||
@@ -2,12 +2,12 @@ apply plugin: VerifyMongoDBConfigurationPlugin
|
||||
|
||||
dependencies {
|
||||
|
||||
testCompile project(":commandside-backend-accounts")
|
||||
testCompile project(":commandside-backend-transactions")
|
||||
testCompile project(":queryside-backend")
|
||||
testCompile project(":accounts-command-side-backend")
|
||||
testCompile project(":transactions-command-side-backend")
|
||||
testCompile project(":accounts-query-side-backend")
|
||||
testCompile project(":testutil")
|
||||
testCompile "junit:junit:4.11"
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||
testCompile "net.chrisrichardson.eventstore.client:eventstore-jdbc:$eventStoreClientVersion"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,6 @@ subprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://06c59145-4e83-4f22-93ef-6a7eee7aebaa.repos.chrisrichardson.net.s3.amazonaws.com" }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import org.gradle.api.*
|
||||
|
||||
|
||||
class VerifyEventStoreEnvironmentPlugin implements Plugin<Project> {
|
||||
void apply(Project project) {
|
||||
project.test {
|
||||
beforeSuite { x ->
|
||||
if (x.parent == null) {
|
||||
if (System.getenv("EVENT_STORE_URL") == null)
|
||||
logger.warn("\nPLEASE make sure that Event Store-related environment variables including EVENT_STORE_URL are set, see sample-set-remote-env.sh !!!!\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
java-spring/e2e-test/build.gradle
Normal file
21
java-spring/e2e-test/build.gradle
Normal file
@@ -0,0 +1,21 @@
|
||||
apply plugin: VerifyMongoDBConfigurationPlugin
|
||||
|
||||
dependencies {
|
||||
compile "org.scala-lang:scala-library:2.10.2"
|
||||
|
||||
testCompile project(":accounts-command-side-web")
|
||||
testCompile project(":transactions-command-side-web")
|
||||
testCompile project(":accounts-query-side-web")
|
||||
|
||||
testCompile "junit:junit:4.11"
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||
testCompile scalaTestDependency
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
ignoreFailures true
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package net.chrisrichardson.eventstore.examples.bank.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.web.commandside.transactions.CreateMoneyTransferRequest;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferResponse;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse;
|
||||
import net.chrisrichardson.eventstore.json.EventStoreCommonObjectMapping;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import rx.Observable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
|
||||
|
||||
public class EndToEndTest {
|
||||
|
||||
private String accountsCommandSideBaseUrl(String path) {
|
||||
return "http://localhost:8080/" + path;
|
||||
}
|
||||
private String accountsQuerySideBaseUrl(String path) {
|
||||
return "http://localhost:8081/" + path;
|
||||
}
|
||||
private String transactionsCommandSideBaseUrl(String path) {
|
||||
return "http://localhost:8082/" + path;
|
||||
}
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
{
|
||||
|
||||
for (HttpMessageConverter<?> mc : restTemplate.getMessageConverters()) {
|
||||
if (mc instanceof MappingJackson2HttpMessageConverter) {
|
||||
((MappingJackson2HttpMessageConverter) mc).setObjectMapper(EventStoreCommonObjectMapping.getObjectMapper());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccountsAndTransferMoney() {
|
||||
|
||||
BigDecimal initialFromAccountBalance = new BigDecimal(500);
|
||||
BigDecimal initialToAccountBalance = new BigDecimal(100);
|
||||
BigDecimal amountToTransfer = new BigDecimal(150);
|
||||
|
||||
BigDecimal finalFromAccountBalance = initialFromAccountBalance.subtract(amountToTransfer);
|
||||
BigDecimal finalToAccountBalance = initialToAccountBalance.add(amountToTransfer);
|
||||
|
||||
final CreateAccountResponse fromAccount = restTemplate.postForEntity(accountsCommandSideBaseUrl("/accounts"), new CreateAccountRequest(initialFromAccountBalance), CreateAccountResponse.class).getBody();
|
||||
final String fromAccountId = fromAccount.getAccountId();
|
||||
|
||||
CreateAccountResponse toAccount = restTemplate.postForEntity(accountsCommandSideBaseUrl("/accounts"), new CreateAccountRequest(initialToAccountBalance), CreateAccountResponse.class).getBody();
|
||||
String toAccountId = toAccount.getAccountId();
|
||||
|
||||
Assert.assertNotNull(fromAccountId);
|
||||
Assert.assertNotNull(toAccountId);
|
||||
|
||||
assertAccountBalance(fromAccountId, initialFromAccountBalance);
|
||||
assertAccountBalance(toAccountId, initialToAccountBalance);
|
||||
|
||||
|
||||
final CreateMoneyTransferResponse moneyTransfer = restTemplate.postForEntity(transactionsCommandSideBaseUrl("/transfers"),
|
||||
new CreateMoneyTransferRequest(fromAccountId, toAccountId, amountToTransfer), CreateMoneyTransferResponse.class).getBody();
|
||||
|
||||
assertAccountBalance(fromAccountId, finalFromAccountBalance);
|
||||
assertAccountBalance(toAccountId, finalToAccountBalance);
|
||||
|
||||
// TOOD - check state of money transfer
|
||||
}
|
||||
|
||||
private BigDecimal toCents(BigDecimal dollarAmount) {
|
||||
return dollarAmount.multiply(new BigDecimal(100));
|
||||
}
|
||||
|
||||
private void assertAccountBalance(final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
|
||||
final BigDecimal inCents = toCents(expectedBalanceInDollars);
|
||||
eventually(
|
||||
new Producer<GetAccountResponse>() {
|
||||
@Override
|
||||
public Observable<GetAccountResponse> produce() {
|
||||
return Observable.just(restTemplate.getForEntity(accountsQuerySideBaseUrl("/accounts/" + fromAccountId), GetAccountResponse.class).getBody());
|
||||
}
|
||||
},
|
||||
new Verifier<GetAccountResponse>() {
|
||||
@Override
|
||||
public void verify(GetAccountResponse accountInfo) {
|
||||
Assert.assertEquals(fromAccountId, accountInfo.getAccountId());
|
||||
Assert.assertEquals(inCents, accountInfo.getBalance());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,5 +5,5 @@ scalaTestDependency=org.scalatest:scalatest_2.10:2.0
|
||||
|
||||
springBootVersion=1.1.10.RELEASE
|
||||
|
||||
eventStoreCommonVersion=0.2
|
||||
eventStoreClientVersion=0.2
|
||||
eventStoreClientVersion=0.5
|
||||
eventStoreCommonVersion=0.5
|
||||
|
||||
@@ -3,9 +3,9 @@ apply plugin: VerifyMongoDBConfigurationPlugin
|
||||
apply plugin: 'spring-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(":queryside-web")
|
||||
compile project(":commandside-web-accounts")
|
||||
compile project(":commandside-web-transactions")
|
||||
compile project(":accounts-query-side-web")
|
||||
compile project(":accounts-command-side-web")
|
||||
compile project(":transactions-command-side-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
||||
@@ -1,20 +1,26 @@
|
||||
include 'testutil'
|
||||
include 'web-common'
|
||||
include 'common-web'
|
||||
|
||||
include 'common-backend'
|
||||
|
||||
include 'commandside-backend-accounts'
|
||||
include 'commandside-backend-transactions'
|
||||
include 'commandside-web-accounts'
|
||||
include 'commandside-web-transactions'
|
||||
include 'accounts-command-side-backend'
|
||||
include 'transactions-command-side-backend'
|
||||
include 'accounts-command-side-web'
|
||||
include 'transactions-command-side-web'
|
||||
|
||||
|
||||
include 'queryside-backend'
|
||||
include 'queryside-web'
|
||||
include 'accounts-query-side-backend'
|
||||
include 'accounts-query-side-web'
|
||||
|
||||
include 'backend-integration-tests'
|
||||
|
||||
include 'monolithic-web'
|
||||
include 'monolithic-service'
|
||||
|
||||
include 'accounts-command-side-service'
|
||||
include 'accounts-query-side-service'
|
||||
include 'transactions-command-side-service'
|
||||
|
||||
include 'e2e-test'
|
||||
|
||||
rootProject.name = 'java-spring-event-sourcing-example'
|
||||
|
||||
|
||||
@@ -12,4 +12,4 @@ dependencies {
|
||||
testCompile "net.chrisrichardson.eventstore.client:eventstore-jdbc:$eventStoreClientVersion"
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ import net.chrisrichardson.eventstore.subscriptions.config.EventStoreSubscriptio
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import net.chrisrichardson.eventstore.javaapi.consumer.EnableJavaEventHandlers;
|
||||
|
||||
@Configuration
|
||||
@Import(EventStoreSubscriptionsConfiguration.class)
|
||||
@EnableEventHandlers
|
||||
@EnableJavaEventHandlers
|
||||
public class MoneyTransferConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -1,11 +1,11 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions;
|
||||
|
||||
|
||||
import net.chrisrichardson.eventstore.javaapi.consumer.EventHandlerContext;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitFailedDueToInsufficientFundsEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent;
|
||||
import net.chrisrichardson.eventstore.subscriptions.CompoundEventHandler;
|
||||
import net.chrisrichardson.eventstore.subscriptions.EventHandlerContext;
|
||||
import net.chrisrichardson.eventstore.subscriptions.EventHandlerMethod;
|
||||
import net.chrisrichardson.eventstore.subscriptions.EventSubscriber;
|
||||
import rx.Observable;
|
||||
20
java-spring/transactions-command-side-service/build.gradle
Normal file
20
java-spring/transactions-command-side-service/build.gradle
Normal file
@@ -0,0 +1,20 @@
|
||||
apply plugin: 'spring-boot'
|
||||
|
||||
apply plugin: VerifyEventStoreEnvironmentPlugin
|
||||
|
||||
dependencies {
|
||||
compile project(":transactions-command-side-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
||||
|
||||
compile "net.chrisrichardson.eventstore.client:eventstore-http-stomp-client:$eventStoreClientVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
ignoreFailures true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import net.chrisrichardson.eventstore.client.config.EventStoreHttpClientConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CommandSideWebTransactionsConfiguration;
|
||||
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;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
|
||||
@Configuration
|
||||
@Import({CommandSideWebTransactionsConfiguration.class, EventStoreHttpClientConfiguration.class})
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class TransactionsCommandSideServiceConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public HttpMessageConverters customConverters() {
|
||||
HttpMessageConverter<?> additional = new MappingJackson2HttpMessageConverter();
|
||||
return new HttpMessageConverters(additional);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.main;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.TransactionsCommandSideServiceConfiguration;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
|
||||
public class TransactionsCommandSideServiceMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TransactionsCommandSideServiceConfiguration.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = TransactionsCommandSideServiceTestConfiguration.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest({"server.port=0", "management.port=0"})
|
||||
public class TransactionsCommandSideServiceIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
|
||||
private String baseUrl(String path) {
|
||||
return "http://localhost:" + port + "/" + path;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
RestTemplate restTemplate;
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccountsAndTransferMoney() {
|
||||
// TBD
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Import(TransactionsCommandSideServiceConfiguration.class)
|
||||
public class TransactionsCommandSideServiceTestConfiguration {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpMessageConverters converters) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
HttpMessageConverter<?> httpMessageConverter = converters.getConverters().get(0);
|
||||
List<? extends HttpMessageConverter<?>> httpMessageConverters = Arrays.asList(new MappingJackson2HttpMessageConverter());
|
||||
restTemplate.setMessageConverters((List<HttpMessageConverter<?>>) httpMessageConverters);
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
dependencies {
|
||||
compile project(":commandside-backend-transactions")
|
||||
compile project(":web-common")
|
||||
compile project(":transactions-command-side-backend")
|
||||
compile project(":common-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
}
|
||||
4
kill-all-services.sh
Executable file
4
kill-all-services.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#! /bin/bash
|
||||
|
||||
kill `cat account-cs.pid account-qs.pid transfers-cs.pid`
|
||||
rm account-cs.pid account-qs.pid transfers-cs.pid
|
||||
31
run-all-services.sh
Executable file
31
run-all-services.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#! /bin/bash -e
|
||||
|
||||
# Execute this script in the java-spring or scala-spring directory
|
||||
# Runs all of the services
|
||||
|
||||
if [[ -f account-cs.pid ]]; then
|
||||
echo pid file exists
|
||||
exit 1
|
||||
fi
|
||||
|
||||
java -jar accounts-command-side-service/build/libs/accounts-command-side-service.jar > account-cs.log &
|
||||
echo $! > account-cs.pid
|
||||
|
||||
java -jar accounts-query-side-service/build/libs/accounts-query-side-service.jar --server.port=8081 > account-qs.log &
|
||||
echo $! > account-qs.pid
|
||||
|
||||
java -jar transactions-command-side-service/build/libs/transactions-command-side-service.jar --server.port=8082 > transfers-cs.log &
|
||||
echo $! > transfers-cs.pid
|
||||
|
||||
echo -n waiting for services....
|
||||
|
||||
while [[ true ]]; do
|
||||
nc -z -w 4 localhost 8080 && nc -z -w 4 localhost 8081 && nc -z -w 4 localhost 8082
|
||||
if [[ "$?" -eq "0" ]]; then
|
||||
echo connected
|
||||
break
|
||||
fi
|
||||
echo -n .
|
||||
sleep 1
|
||||
done
|
||||
|
||||
6
run-e2e-test-all.sh
Executable file
6
run-e2e-test-all.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#! /bin/bash -e
|
||||
|
||||
for dir in java-spring scala-spring; do
|
||||
(cd $dir ; ../run-e2e-test.sh)
|
||||
done
|
||||
|
||||
16
run-e2e-test.sh
Executable file
16
run-e2e-test.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash -e
|
||||
|
||||
# Must be run in the java-spring or scala-spring directories
|
||||
|
||||
echo starting services
|
||||
|
||||
../run-all-services.sh
|
||||
|
||||
echo running test
|
||||
|
||||
./gradlew :e2e-test:cleanTest :e2e-test:test
|
||||
|
||||
echo killing services
|
||||
|
||||
../kill-all-services.sh
|
||||
|
||||
9
sample-set-server-env.sh
Executable file
9
sample-set-server-env.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#! /bin/bash -e
|
||||
|
||||
export EVENT_STORE_USER_ID=Aladdin
|
||||
export EVENT_STORE_PASSWORD="open sesame"
|
||||
export EVENT_STORE_URL=serverUrl
|
||||
export EVENT_STORE_STOMP_SERVER_HOST=serverhost
|
||||
export EVENT_STORE_STOMP_SERVER_PORT=serverPort
|
||||
|
||||
export SPRING_DATA_MONGODB_URI=mongodb://192.168.59.103/mydb
|
||||
@@ -1,5 +1,7 @@
|
||||
This is the Scala/Spring version of the Event Sourcing/CQRS money transfer example application.
|
||||
|
||||
# About the application
|
||||
|
||||
This application consists of three microservices:
|
||||
|
||||
* Account Service - the command side business logic for Accounts
|
||||
@@ -8,25 +10,28 @@ This application consists of three microservices:
|
||||
|
||||
The Account Service consists of the following modules:
|
||||
|
||||
* commandside-backend-accounts - the Account aggregate
|
||||
* commandside-web-accounts - a REST API for creating and retrieving Accounts
|
||||
|
||||
* 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:
|
||||
|
||||
* commandside-backend-transactions - the MoneyTransfer aggregate
|
||||
* commandside-web-transactions - a REST API for creating and retrieving Money Transfers
|
||||
* 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:
|
||||
|
||||
* queryside-backend - MongoDB-based, denormalized view of Accounts and MoneyTransfers
|
||||
* queryside-web - a REST API for querying the denormalized view
|
||||
* accounts-query-side-backend - MongoDB-based, denormalized view of Accounts and MoneyTransfers
|
||||
* accounts-query-side-web - a REST API for querying the denormalized view
|
||||
* accounts-query-side-service - a standalone microservice
|
||||
|
||||
In order to be used with the embedded Event Store, the three services are currently packaged as a single monolithic web application:
|
||||
# Deploying the application
|
||||
|
||||
* monolithic-web - all-in-one, monolithic packaging of 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.
|
||||
|
||||
As well as the above modules there are also:
|
||||
The three services can also be packaged as a single monolithic web application in order to be used with the embedded Event Store:
|
||||
|
||||
* common-backend - code that is shared between the command side and the query side, primarily events and value objects
|
||||
* backend-integration-tests - integrations tests for the backend
|
||||
|
||||
* monolithic-service - all-in-one, monolithic packaging of the application
|
||||
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@ dependencies {
|
||||
compile "org.scala-lang:scala-library:2.10.2"
|
||||
compile project(":common-backend")
|
||||
compile "net.chrisrichardson.eventstore.client:eventstore-client-event-handling:$eventStoreClientVersion"
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,8 @@ class TransferWorkflowAccountHandlers(eventStore: EventStore) extends CompoundEv
|
||||
|
||||
@EventHandlerMethod
|
||||
val performCredit = handlerForEvent[DebitRecordedEvent] { de =>
|
||||
existingEntity[Account](de.event.details.toAccountId) <== CreditAccountCommand(de.event.details.amount, de.entityId)
|
||||
existingEntity[Account](de.event.details.toAccountId) <==
|
||||
CreditAccountCommand(de.event.details.amount, de.entityId)
|
||||
}
|
||||
|
||||
}
|
||||
22
scala-spring/accounts-command-side-service/build.gradle
Normal file
22
scala-spring/accounts-command-side-service/build.gradle
Normal file
@@ -0,0 +1,22 @@
|
||||
apply plugin: 'scala'
|
||||
apply plugin: 'spring-boot'
|
||||
apply plugin: VerifyEventStoreEnvironmentPlugin
|
||||
|
||||
dependencies {
|
||||
compile "org.scala-lang:scala-library:2.10.2"
|
||||
compile project(":accounts-command-side-web")
|
||||
|
||||
compile "org.springframework.boot:spring-boot-starter-web"
|
||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
||||
|
||||
compile "net.chrisrichardson.eventstore.client:eventstore-http-stomp-client:$eventStoreClientVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
testCompile scalaTestDependency
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
ignoreFailures true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.chrisrichardson.eventstore.examples.bank.web
|
||||
|
||||
import net.chrisrichardson.eventstore.client.config.EventStoreHttpClientConfiguration
|
||||
import net.chrisrichardson.eventstore.examples.bank.web.accounts.CommandSideWebAccountsConfiguration
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.context.annotation._
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@Import(Array(classOf[CommandSideWebAccountsConfiguration], classOf[EventStoreHttpClientConfiguration]))
|
||||
@ComponentScan
|
||||
class AccountsCommandSideServiceConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.chrisrichardson.eventstore.examples.bank.web.main
|
||||
|
||||
import net.chrisrichardson.eventstore.examples.bank.web.AccountsCommandSideServiceConfiguration
|
||||
import org.springframework.boot.SpringApplication
|
||||
|
||||
object AccountsCommandSideServiceMain {
|
||||
|
||||
def main(args: Array[String]) : Unit = SpringApplication.run(classOf[AccountsCommandSideServiceConfiguration], args :_ *)
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user