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:
Chris Richardson
2015-04-14 19:08:07 -07:00
parent d166c9b852
commit 2e31853ad2
150 changed files with 1237 additions and 109 deletions

View File

@@ -0,0 +1,19 @@
apply plugin: 'scala'
dependencies {
compile project(":common-backend")
compile "org.scala-lang:scala-library:2.10.2"
compile "org.springframework.boot:spring-boot-starter-data-mongodb:$springBootVersion"
compile "net.chrisrichardson.eventstore.common:eventstore-common:$eventStoreCommonVersion"
compile "net.chrisrichardson.eventstore.client:eventstore-client-event-handling:$eventStoreClientVersion"
testCompile scalaTestDependency
testCompile "junit:junit:4.11"
testCompile "net.chrisrichardson.eventstore.client:eventstore-jdbc:$eventStoreClientVersion"
}

View File

@@ -0,0 +1,14 @@
package net.chrisrichardson.eventstore.examples.bank.queryside
import org.springframework.data.mongodb.repository.MongoRepository
case class AccountInfo(id : String, balance : Long,
changes : java.util.List[AccountChangeInfo],
transactions : java.util.List[AccountTransactionInfo],
version : String)
case class AccountChangeInfo(changeId : String, transactionId : String, transactionType : String, amount : Long, balanceDelta: Long)
case class AccountTransactionInfo(transactionId : String, fromAccountId: String, toAccountId: String, amount : Long)
trait AccountInfoRepository extends MongoRepository[AccountInfo, String]

View File

@@ -0,0 +1,17 @@
package net.chrisrichardson.eventstore.examples.bank.queryside
import net.chrisrichardson.eventstore.EntityId
class AccountInfoQueryService(accountInfoRepository : AccountInfoRepository) {
def findByAccountId(accountId : EntityId) : AccountInfo = {
val account = accountInfoRepository.findOne(accountId.id)
if (account == null)
throw new AccountNotFoundException(accountId)
else
account
}
}
class AccountNotFoundException(accountId : EntityId) extends RuntimeException("Account not found " + accountId)

View File

@@ -0,0 +1,95 @@
package net.chrisrichardson.eventstore.examples.bank.queryside
import net.chrisrichardson.eventstore.EntityId
import net.chrisrichardson.eventstore.Event
import net.chrisrichardson.eventstore.Event.EventId
import net.chrisrichardson.eventstore.examples.bank.backend.common.transactions.MoneyTransferCreatedEvent
import net.chrisrichardson.eventstore.examples.bank._
import net.chrisrichardson.eventstore.examples.bank.backend.common.accounts._
import net.chrisrichardson.eventstore.subscriptions.{EventSubscriber, DispatchedEvent, EventHandlerMethod, CompoundEventHandler}
import net.chrisrichardson.eventstore.util.ServiceUtil._
import net.chrisrichardson.utils.logging.Logging
import org.springframework.data.mongodb.core.MongoTemplate
import scala.collection.JavaConversions._
import org.springframework.data.mongodb.core.query.Criteria.where
import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.mongodb.core.query.Update
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
@EventSubscriber (id = "querySideEventHandlers")
class AccountInfoUpdateService(accountInfoRepository : AccountInfoRepository, mongoTemplate : MongoTemplate) extends CompoundEventHandler with Logging {
@EventHandlerMethod
def created(de: DispatchedEvent[AccountOpenedEvent]) = Future {
logger.info("About to save")
try {
if (de.event.initialBalance != null)
accountInfoRepository.save(AccountInfo(de.entityId.id, toIntegerRepr(de.event.initialBalance), Seq(), Seq(), de.eventId.asString))
else
logger.error("Event with initialBalance == null {}", de.entityId)
}
catch {
case t : Throwable =>
logger.error("Error during saving: ")
logger.error("Error during saving: ", t)
throw t
}
logger.info("Saved in mongo")
}
@EventHandlerMethod
def recordDebit(de: DispatchedEvent[AccountDebitedEvent]) = saveChange(de, -1)
@EventHandlerMethod
def recordCredit(de: DispatchedEvent[AccountCreditedEvent]) = saveChange(de, +1)
@EventHandlerMethod
def recordDebitFailed(de: DispatchedEvent[AccountDebitFailedDueToInsufficientFundsEvent]) = saveChange(de, 0)
def toIntegerRepr(d : BigDecimal) = (d * 100).toLong
def saveChange[T <: AccountChangedEvent](de : DispatchedEvent[T], delta : Int) = Future {
val changeId = de.eventId.asString
val transactionId = de.event.transactionId.id
val amount = toIntegerRepr(de.event.amount)
val ci= AccountChangeInfo(changeId, transactionId, de.event.getClass.getSimpleName, amount, amount * delta)
mongoTemplate.updateMulti(new Query(where("id").is(de.entityId.id).and("version").lt(changeId)),
new Update().
inc("balance", amount * delta).
push("changes", ci).
set("version", changeId),
classOf[AccountInfo])
}
@EventHandlerMethod
def recordTransfer(de: DispatchedEvent[MoneyTransferCreatedEvent]) = Future {
val eventId = de.eventId.asString
val fromAccountId = de.event.details.fromAccountId.id
val toAccountId = de.event.details.toAccountId.id
val ti = AccountTransactionInfo(de.entityId.id, fromAccountId, toAccountId, toIntegerRepr(de.event.details.amount))
mongoTemplate.updateMulti(new Query(where("id").is(fromAccountId).and("version").lt(eventId)),
new Update().
push("transactions", ti).
set("version", eventId),
classOf[AccountInfo])
mongoTemplate.updateMulti(new Query(where("id").is(toAccountId).and("version").lt(eventId)),
new Update().
push("transactions", ti).
set("version", eventId),
classOf[AccountInfo])
}
}

View File

@@ -0,0 +1,20 @@
package net.chrisrichardson.eventstore.examples.bank.queryside
import org.springframework.context.annotation.{Bean, Configuration}
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories
@Configuration
@EnableMongoRepositories
class QuerySideConfiguration {
@Bean
def accountUpdateService(accountInfoRepository: AccountInfoRepository, mongoTemplate: MongoTemplate): AccountInfoUpdateService =
new AccountInfoUpdateService(accountInfoRepository, mongoTemplate)
@Bean
def accountInfoQueryService(accountInfoRepository : AccountInfoRepository) = new AccountInfoQueryService(accountInfoRepository)
@Bean
def querysideDependencyChecker(mongoTemplate : MongoTemplate) = new QuerysideDependencyChecker(mongoTemplate)
}

View File

@@ -0,0 +1,26 @@
package net.chrisrichardson.eventstore.examples.bank.queryside
import javax.annotation.PostConstruct
import net.chrisrichardson.utils.logging.Logging
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.mongodb.core.MongoTemplate
import scala.concurrent.{TimeoutException, Await, Future}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
class QuerysideDependencyChecker (mongoTemplate : MongoTemplate) extends Logging {
@PostConstruct
def checkDependencies(): Unit = {
try {
Await.result(Future { mongoTemplate.getDb.getCollectionNames}, 5 seconds)
} catch {
case e : Throwable =>
logger.error("Error connecting to Mongo - have you set SPRING_DATA_MONGODB_URI or --spring.data.mongodb_uri?", e)
throw e
}
}
}