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:
19
scala-spring/accounts-query-side-backend/build.gradle
Normal file
19
scala-spring/accounts-query-side-backend/build.gradle
Normal 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"
|
||||
}
|
||||
|
||||
|
||||
@@ -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]
|
||||
@@ -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)
|
||||
@@ -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])
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user