Introducing
Your new presentation assistant.
Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.
Trending searches
Association
Notice that links points to source code in repo: http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample
Serializes Commands to JSON
Not important, all interesing stuff happends in Controler - Presentation Layer in Server Tier
Sends Commands to the Server Gate
- mobile client can be occasionally connected
- so it can queue commands (those which are annotated as offlineSupport=true) if there is no connection
- when connection is established it sends queued commands
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fwebapp
pl.com.bottega.erp.sales.webui
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fwebui
pl.com.bottega.erp.sales
pl.com.bottega.erp.crm
pl.com.bottega.erp.shipping
It's always handfull and productive
to use some CRUD Framework
for simple Use Cases (ex. Supporting Domains)
a) classic way: calls Application Serivce
b) cqrs way: creates Command and sends it to the Gate
Client knows if he is interested in immediate Command Execution. If not, than You annotate Command with asynchronous=true parameter
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fcrm
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fshipping
You can annotate Command classes with pl.com.bottega.cqrs.command.Command in order to introduce:
- duplication checking
- asynchronous handling
pl.com.bottega.erp.sales.application.commands
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fapplication%2Fcommands
Contains list of product IDs
Contains order ID
May contain for example:
- payment
- shipment address
- ect
Business (Write) Model
Presentation (Read) Model
pl.com.bottega.cqrs.command
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Fcqrs%2Fcommand
pl.com.bottega.cqrs.command.Gate
pl.com.bottega.cqrs.command.RunEnvironment
pl.com.bottega.cqrs.command.handler.CommandHandler
Base interface for Handlers, specyfying two generic types:
- C - command type
- R - result type (should be Void for asynch. commands)
Stores X last commands that were ran (commands that are annotated as "unique").
equals() method decides if commands are the same
For example: approving order with the same ID twice does not make any sense.
Warning: History is just an optimisation - You must check rules also in domain model
Main Responsibility:
- find relevant Command Handler and run it passing given Command
This is also a perfect place to introduce additional features before and after running a Handler:
- injecting dependencies into a Command handler (if You don't want to use IoC container like Spring IoC)
- handle transactions, security ect. (if You don't want to use AOP techniques like Spring AOP)
- profiling
- logging
- syping:)
We suggest to annotate each Handler with: pl.com.bottega.cqrs.command.handler.CommandHandlerAnnotation
Resposibility:
- main gate to the Server
- optimisation such as: rejecting command duplicates, dispatching asynch. commands to the queue
1. If Command is annotaed as "unique" than checks in History if the given command was already ran
- If so, than reject Command
2. If Command is annotated as "asynchronous" than sends given command to the Queue and returns
3. Sends Command to the Run Environment
RunEnvironment delegats this problem to the HandlersProvider
Simplest way is to use HashMap:
- key is a Command class
- value is a CommandHandler
1. This handler scans all Spring Beans
2. If bean implements CommandHandler interface than that's our guy
3. We check Generic type of that class - type of handled Command
4. We simply register this information in a hashmap
- key is a Command class
- value is a Spring Bean name
pl.com.bottega.erp.sales.presentation
pl.com.bottega.erp.sales.application
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fapplication
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fpresentation
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fapplication%2Fcommands%2Fhandlers
pl.com.bottega.erp.sales.application.commands.handlers
Command Handler responsibility: orchestrate Domain Objects to fullfill part of the UseCase/UserStory
CH contains needed dependencies (ex. Repositories, ) that are Injected by:
- IoC Container (ex. Spring) - if CH is managed by some container
- RunEnvironment - if You don't want to inroduce any container
pl.com.bottega.erp.sales.application.listeners
pl.com.bottega.erp.sales.application.services
Handles Events from another Bounded Contexts (modules)
- used to decouple modules
- can be considered as an Anticorruption Layer or Context Mapper
This kind of Listeners can issue a command to this Bounded Context (Module) or simply perform some logic just like CommandHandlers do.
App Service has the same responsibility as a Command Handler: orchestrate Domain Objects to fullfill part of the UseCase/UserStory
AS may use AOP to assure Security, transactions, ect.
Functionality similar to Handlers
If a customer becomes a VIP then calculate x% rebate for all his orders that are in DRAFT status
pl.com.bottega.erp.sales.application.events
Sample objects that are obly concepts of Application (model of some Application Features).
pl.com.bottega.ddd.application
contains info about
- cleint ID
- product ID
- quantity
lets assume that we want to spy clients only in this Use Case
An application concept introduced to model convenient feature of the Application. In this Sample We assume that this in not a Domain concept (but in some business domain it may be).
pl.com.bottega.erp.crm.domain
pl.com.bottega.erp.sales.domain.specification.order
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fcrm%2Fdomain
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fdomain
Encapsulates Business Logic that determines which impl should be used.
Uses injected SystemUser to make this decission.
Encapsulates representation (BigDecimal or shifted int) and Currency
Encapsulates Domain Logic which does not belong to any Aggreagte
We don't want to have generateInvoice() method in Order class bacause We don't want Order to become a 'God Class'
private Money net
private Money gros
private List<InvoiceLine> items;
private Money totalCost;
private List<OrderLine> items;
public void addProduct(Product, quantity)
public void submit()
public List<OrderedProduct> getOrderedProducts()
Introduced to encapsulate inner Aggreate Impl - in particural OrderLine model which is assumed to be unstable in this moment of time
Encapsulated concept.
We assume that this model is not stable (will change), so we make a "projction" using ValueObjects
public void changeStatus(Status newStatus)
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fshipping%2Fdomain%2Fevents
pl.com.bottega.erp.sales.domain.specification.order
Encapsulates Tree of Rules that determine if given Order can be submitted
Contains:
- customerId
- status
pl.com.bottega.erp.sales.infrastructure
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Finfrastructure
pl.com.bottega.erp.sales.infrastructure.events.listeners.application
pl.com.bottega.erp.sales.infrastructure.repositories.jpa
pl.com.bottega.erp.sales.infrastructure.events.listeners.domain
Sample Repositories
Can perform additional logic (ex. sending email)
Can perform additional logic (ex. sending email)
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Fddd%2Fsagas
pl.com.bottega.erp.sales.saga
pl.com.bottega.ddd.sagas
pl.com.bottega.ddd.infrastructure.events
Saga is a:
model of complex (distributed) Business Process
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Fddd%2Finfrastructure%2Fevents
Impl of Events Engine.
Here is how it works:
pl.com.bottega.ddd.infrastructure.events.impl.EventListenerBeanPostProcessor
scans all Spring Beans.
If bean contains metohod annotated @EventListener than that's our guy. We simply check parameter of this method and register it in:
pl.com.bottega.ddd.infrastructure.events.impl.SimpleEventPublisher
which is both Domain and Application Event publisher.
So when You fire an event You actually speak to this guy.
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fsaga
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Fddd%2Finfrastructure%2Fsagas
pl.com.bottega.ddd.infrastructure.sagas
Impl of Saga Engine.
Sagas engine is simply one of the Event listeners.
At system start Saga Engine scans all Saga Beans and finds out which Events they are interested in.
For each event Saga Engine registeres itself as an listener in Events Engine.
Use
pl.com.bottega.ddd.infrastructure.events.EventListener
to annotate listener methods
It is opposite way as in case of Commands where client sending a Command could express asynchronous intention - it was ouside of the Handler knowledge scope.
Stores Domain Events
pl.com.bottega.erp.sales.presentation.listeners
http://code.google.com/p/ddd-cqrs-sample/source/browse/#svn%2Ftrunk%2Fddd_cqrs-sample%2Fsrc%2Fmain%2Fjava%2Fpl%2Fcom%2Fbottega%2Ferp%2Fsales%2Fpresentation%2Flisteners