Permalink
Browse files

Documentation update

  • Loading branch information...
1 parent d16ae6f commit 67c6b3b22a4db7f7fbbe9b6cb6932babcd31b3e1 @krasserm krasserm committed Oct 25, 2012
View
@@ -1,26 +1,31 @@
Overview
--------
-This project re-implements [eventsourcing-example](https://github.com/krasserm/eventsourcing-example) based on the Eligosource [Eventsourced](https://github.com/eligosource/eventsourced) library. Regarding library usage, it demonstrates how to
+This project demonstrates how to implement an [event-sourced](http://martinfowler.com/eaaDev/EventSourcing.html) web application based on the Eligosource [Eventsourced](https://github.com/eligosource/eventsourced) library. It is based on [former work](https://github.com/krasserm/eventsourcing-example) that has been described in the articles
-- implement command-sourcing (for managing state of invoices)
-- implement event-sourcing (for managing state of payment processes and for recording usage statistics)
-- implement domain services (to handle requests via UI and XML/JSON API)
-- implement business processes (to deal with long-running background activities)
-- recover from crashes (incl. recovery of business processes)
+- [Building an Event-Sourced Web Application - Part 1: Domain Model, Events and State](http://krasserm.blogspot.com/2011/11/building-event-sourced-web-application.html)
+- [Building an Event-Sourced Web Application - Part 2: Projections, Persistence, Consumers and Web Interface](http://krasserm.blogspot.com/2012/01/building-event-sourced-web-application.html)
-Compared to the [old implementation](https://github.com/krasserm/eventsourcing-example), the whole service and persistence layer are re-written and domain events are now decoupled from the immutable domain model. The web UI and XML/JSON API remain unchanged and are built on top of [Jersey](http://jersey.java.net/), [Scalate](http://scalate.fusesource.org/) and [JAXB](http://jcp.org/en/jsr/detail?id=222). A [Play](http://www.playframework.org/)-based version will follow (which supports asynchronous responses in contrast to Jersey).
+Compared to the [old implementation](https://github.com/krasserm/eventsourcing-example), the whole service and persistence layer have been re-written and the domain events are now decoupled from the immutable domain model. The web UI and the web API remain unchanged.
-Architecture
-------------
+The example web application uses the [Eventsourced](https://github.com/eligosource/eventsourced) library for both event-sourcing and command-sourcing. Furthermore, it implements the [CQRS](http://martinfowler.com/bliki/CQRS.html) pattern and follows [domain-driven design](http://domaindrivendesign.org/resources/what_is_ddd) principles.
-![Architecture](https://raw.github.com/eligosource/eventsourced-example/master/doc/images/invoice-example.png)
+![Architecture](https://raw.github.com/eligosource/eventsourced-example/wip-es-trait/doc/images/architecture.png)
-### State management
+Legend:
-- Command and event-sourced processors manage state via [STM](http://en.wikipedia.org/wiki/Software_transactional_memory) references.
-- For reading current state, services access STM references directly (concurrent reads).
-- For updating current state, services access STM references via processors (actors) where a single STM reference is updated by a single processor ([single-writer-principle](http://mechanical-sympathy.blogspot.de/2011/09/single-writer-principle.html)).
+![Legend](https://raw.github.com/eligosource/eventsourced/wip-es-trait/doc/images/legend.png)
+
+- The [domain model](https://github.com/eligosource/eventsourced-example/blob/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/domain/Invoice.scala) is a rich, immutable domain model. It is annotated with [JAXB](http://jcp.org/en/jsr/detail?id=222) annotations for XML and JSON binding.
+- The [service layer](https://github.com/eligosource/eventsourced-example/tree/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/service) implements the event-sourced and command-sourced actors (processors) together with service facades for asynchronous writes and synchronous, non-blocking reads of application state.
+ - Processors manage application state via [STM](http://nbronson.github.com/scala-stm/) references.
+ - For reading current state, services facades access STM references directly (concurrent reads).
+ - For updating current state, services facades access STM references via processors where a single STM reference is updated by a single processor ([single-writer-principle](http://mechanical-sympathy.blogspot.de/2011/09/single-writer-principle.html))
+ - On the command-side of the implemented CQRS pattern is the [InvoiceService](https://github.com/eligosource/eventsourced-example/blob/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/service/InvoiceService.scala) that manages application state and serves consistent reads of invoices.
+ - On the query side of the implemented CQRS pattern is the [StatisticsService](https://github.com/eligosource/eventsourced-example/blob/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/service/StatisticsService.scala), a read model that serves eventually consistent reads about invoice update statistics.
+ - The [PaymentProcess](https://github.com/eligosource/eventsourced-example/blob/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/service/PaymentGateway.scala) is an example of a stateful, potentially long-running and event-sourced business process.
+- The [web layer](https://github.com/eligosource/eventsourced-example/tree/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/web) provides a RESTful service interface to application resources and supports HTML, XML and JSON representation formats. It is built on top of [Jersey](http://jersey.java.net/) and [Scalate](http://scalate.fusesource.org/). A [Play](http://www.playframework.org/)-based version will follow (which supports asynchronous responses in contrast to Jersey).
+- The [application configuration](https://github.com/eligosource/eventsourced-example/blob/wip-es-trait/src/main/scala/org/eligosource/eventsourced/example/server/Appserver.scala) wires the pieces together.
Build
-----
@@ -40,20 +45,19 @@ Then checkout the example application and compile it
Run
---
-To start the example application enter
+To start the example application run
sbt 'run-nobootcp org.eligosource.eventsourced.example.server.Webserver'
-Finally go to [http://localhost:8080](http://localhost:8080) and create some invoices.
+Then go to [http://localhost:8080](http://localhost:8080) and create some invoices.
-Web API
--------
+…
-The example application's RESTful service interface supports HTML, XML and JSON as representation formats. Content negotiation is done via the `Accept` HTTP header. The following examples show how to get different representations of `invoice-3`
+The example application's RESTful service interface supports HTML, XML and JSON representation formats. Content negotiation is done via the `Accept` HTTP header. The following examples show how to get HTML and XML representations for `invoice-3`.
### HTML
-Enter [http://localhost:8080/invoice/invoice-3](http://localhost:8080/invoice/invoice-3) into your browser. Provided you have created an invoice with id `invoice-3` before you should see something like
+Click on [http://localhost:8080/invoice/invoice-3](http://localhost:8080/invoice/invoice-3). Provided you have created an invoice with id `invoice-3` before, you should see something like
![invoice-3](https://github.com/krasserm/eventsourcing-example/raw/master/doc/images/invoice-3.png)
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Deleted file not rendered
@@ -24,7 +24,7 @@ import org.eligosource.eventsourced.example.domain._
/**
* Payment gateway that interacts with customer to request payment (mocked).
*/
-class PaymentGateway(invoiceProcessor: ActorRef) extends Actor { this: Receiver =>
+class PaymentGateway(invoiceProcessor: ActorRef) extends Actor {
implicit val executor = context.system.dispatcher
def receive = {
@@ -26,7 +26,7 @@ class StatisticsService(statisticsRef: Ref[Map[String, Int]]) {
def statistics = statisticsRef.single.get
}
-class StatisticsProcessor(statisticsRef: Ref[Map[String, Int]]) extends Actor { this: Receiver =>
+class StatisticsProcessor(statisticsRef: Ref[Map[String, Int]]) extends Actor {
def receive = {
case InvoiceItemAdded(id, _) => statisticsRef.single.transform { statistics =>
statistics.get(id) match {

0 comments on commit 67c6b3b

Please sign in to comment.