tag:blogger.com,1999:blog-33146017223220987652023-11-16T12:07:40.174+01:00Sculptor Team BlogSculptor is an open source productivity tool. You express your design intent in a textual DSL, from which Sculptor generates high quality Java code and configuration.Sculptorhttp://www.blogger.com/profile/15660077990398682094noreply@blogger.comBlogger70125tag:blogger.com,1999:blog-3314601722322098765.post-9743456172360729752014-01-24T22:03:00.000+01:002014-01-24T22:03:20.564+01:00Sculptor 3.0 has a new homeStarting with the <a href="http://sculptorgenerator.org/2013/11/29/sculptor-300---a-major-overhaul/">release of version 3.0</a> Sculptor has its new home at <a href="http://sculptorgenerator.org/">http://sculptorgenerator.org/</a>.<br />
<br />
The development is moved to GitHub <a href="https://github.com/sculptor">https://github.com/sculptor</a> and the <a href="http://sculptorgenerator.org/archive">new blog</a> is hosted there as well.<br />
<br />
So take a look at <a href="http://sculptorgenerator.org/">Sculptors new home</a>!Sculptorhttp://www.blogger.com/profile/15660077990398682094noreply@blogger.comtag:blogger.com,1999:blog-3314601722322098765.post-67377368250332168172012-01-21T23:49:00.003+01:002012-01-22T00:13:03.583+01:00Sculptor 2.1.0 ReleasedOne very useful new feature is the generated finder methods. It is now possible to specify the query in the model file and let sculptor generate the code for the repository operations. In some cases the query can be derived from the method signature only.<br /><br />This will generate a query returning all persons with the specified first name.<br /><pre class="brush:text"><br />Entity Person {<br /> String firstName<br /> String lastName<br /> Date birthDate<br /><br /> PersonRepository {<br /> findBy(String firstName);<br /> }<br />}<br /></pre><br /><br />More advanced conditions can also be specified<br /><pre class="brush:text"><br /><br /> PersonRepository {<br /> findBornBefore(Date bd) condition="birthDate < :bd" orderBy="firstName";<br /> findByName(String name) condition="lastName i= :name or firstName i= :name";<br /> }<br /><br /></pre><br /><br />Sculptor generates findByCondition expressions and will report at generation time if there are any errors in the queries.<br /><br /><br />Another nice addition is the generated builder classes that provides a fluent interface to build domain objects in a manner that can be easier to work with and read.<br /><br /><pre class="brush:java"><br /> Book book = book()<br /> .createdBy("me")<br /> .createdDate(now)<br /> .title("Ender's Game")<br /> .isbn("Some-ISBN")<br /> .addMediaCharacter(mediaCharacter()<br /> .name("Ender")<br /> .build())<br /> .build();<br /></pre><br /><br /><a href="http://fornax.itemis.de/confluence/display/fornax/0.+What%27s+New+%28CSC%29#0.What%27sNew%28CSC%29-Version2.1.x">Read more about the release</a>.Sculptorhttp://www.blogger.com/profile/15660077990398682094noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-33190310083896988102011-03-14T21:24:00.002+01:002011-03-14T21:54:14.866+01:00Sculptor 2.0 is outThis is the 11th major release of Sculptor. <br /><br />Three new and noteworthy features:<br /><br />1. The new <a href="http://fornax.itemis.de/confluence/x/BACB">REST support</a> in Sculptor makes it very easy to expose restful services by using conventions and easy delegation to Services to reduce boilerplate coding. <a href="http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html">Spring MVC</a> is the underlaying REST framework. <br /><br />2. <a href="http://fornax-sculptor.blogspot.com/2011/02/mixin-composition.html">Mixin composition</a> is something Java developers are missing, but with Sculptor it becomes available.<br /><br />3. The services can now easily be used with <a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/remoting.html">Spring Remoting</a>. This is convenient for the <a href="http://fornax.itemis.de/confluence/x/zQk">RCP client</a>, but can be used for other clients also.<br /><br />In addition to these and several other new features we have also improved the technical quality.<br /><br />We have upgraded support for latest versions of most of the underlaying tools and frameworks. Most important is Xtext 1.0, Eclipse Helios, Maven 3, Spring 3.0.<br /><br />The logging API has been changed from Commons Logging with Log4j to <a href="http://www.slf4j.org/">SLF4J</a> with <a href="http://logback.qos.ch/">Logback</a>. SLF4J allow many backends and also have special bridges for many (legacy) logging frameworks. SLF4J with Logback is considered to be best logging framework available.Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-31915904226018083882011-02-03T22:00:00.003+01:002011-02-03T22:21:26.801+01:00Mixin CompositionI think one of the best features in Scala is traits. Using traits it is possible to compose small pieces of behavior and state in an elegant way. I miss traits when I use Java. To mitigate that problem I have implemented support for traits in Sculptor. This article illustrates how this tool can be used for designing good, rich, domain models with traits.<br /><br />Traits provide a mixin composition mechanism that is missing in Java. Similar to interfaces in Java, traits are used to define object types by specifying the signature of the supported methods. Unlike interfaces, traits can be partially implemented; i.e. it is possible to define implementations for some methods. Similar to abstract classes, but you don't have to wast your single inheritance opportunity.<br /><br />How many times have you stared at java code like this:<br />if (p1.compareTo(p2) <= 0)<br /><br />Why not spell it out, to make the code more readable:<br />if (p1.lessThanOrEquals(p2))<br /><br />We seldom do that, because implementing 4 methods, lessThan, lessThanOrEquals, greaterThan and greaterThanOrEquals, in each and every class that needs to be compared is too much work. We stick to the cryptical compareTo.<br /><br />What if I say you only have to implement them once and then you can easily mixin the methods in each and every class that needs to be compared or sorted in some way.<br /><br />I hope I don't have to elaborate on how bad idea it is to try to use inheritance (base class) for these kind of reusable pieces of code.<br /><br />In Sculptor's textual DSL model traits are defined like this:<br /><pre class="brush:text"><br /> Trait Ordered {<br /> def boolean greaterThan(@Ordered other);<br /> def boolean greaterThanOrEquals(@Ordered other);<br /> def boolean lessThan(@Ordered other);<br /> def boolean lessThanOrEquals(@Ordered other);<br /> def abstract protected int compare(@Ordered other);<br /> }<br /> <br /> Entity Product with Ordered {<br /> String name<br /> }<br /></pre><br />After code generation this means that you can implement the 4 comparison methods once, in the Ordered trait, and they will be available in Product and other domain objects that are defined 'with Ordered'. The compare method must still be implemented in Product, because it is there you know what to compare with. The internal, generated, implementation is based on delegation, i.e. no magic.<br /><br />Let us define another trait, which illustrates that traits also can hold state.<br /><pre class="brush:text"><br /> Trait PriceTag {<br /> - protected Money normalPrice<br /> protected double discount<br /> def Money price;<br /> def Money price(String currency);<br /> }<br /><br /> Entity Product with PriceTag {<br /> String name<br /> }<br /><br /> BasicType Money with Ordered {<br /> BigDecimal amount<br /> String currency<br /> }<br /></pre><br />This means that normalPrice and discount will be mixed in to Product. You implement the price methods in the PriceTag trait. Product and all other domain objects that are defined 'with PriceTag' will have those fields and methods.<br /><br />Wouldn't it be nice to be able to compare product by price? Let us do that by combining the two traits. First add the compare method in PriceTag, so that you only have to implement it at one place.<br /><pre class="brush:text"><br /> Trait PriceTag {<br /> - protected Money normalPrice<br /> protected double discount<br /> def Money price;<br /> def Money price(String currency);<br /> def protected int compare(Ordered other);<br /> }<br /></pre><br />Then mixin both traits into Product<br /><pre class="brush:text"><br /> Entity Product with Ordered with PriceTag {<br /> String name<br /> }<br /><br /></pre><br />That's it. We have designed products with a rich price and compare interface.<br />Note that compareTo is no longer implemented in Product, only in PriceTag.<br /><br />Try this new feature in latest <a href="http://sculptor.fornax-platform.org">Sculptor</a> 2.0.0-SNAPSHOT.Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com3tag:blogger.com,1999:blog-3314601722322098765.post-51048587953030784472011-01-27T08:32:00.005+01:002011-01-27T09:01:29.176+01:00EDA in Massive Web SitesThis is a comment to <a href="http://twitter.com/h3nk3">@h3nk3</a>'s latest blog post on <a href="http://r-c-r.tumblr.com/post/2947120096/concurrency-parallelism-and-actors">Concurrency, Parallelism and Actors</a>.<br /><br />I totally agree that there is no single solution for everything. Regarding massive web sites I would like to add a few things to your conclusions, which makes asynchronous event driven solutions important for web sites also.<br /><br />You should try to do as little as possible in the request thread, i.e. minimize latency. Threads in them selves are a scarce resource. You can do the essential validation and then hand off the rest of the work to a task queue (e.g. Flickr). You can precompute everything and cache it so that serving the requests becomes trivial (e.g. Reddit). Both these techniques can benefit from using event driven solutions in the backend.<br /><br />We see great improvements in the area of truly asynchronous web solutions, which means that you don't have to deliver a synchronous response to every request. The result can be pushed to the clients asynchronously. Then it becomes natural to use event driven solutions in the server. The reasons for using Actors it is not only scalability and concurrency, it is also much about using a simpler concurrency model than threads and locks.<br /><br />Of course it is also important to use HTTP as designed, since HTTP caching is a key ingredient in highly scalable web sites.Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-25948809178314991042010-10-29T22:00:00.002+02:002010-10-29T22:15:25.567+02:00Event Sourcing with Sculptor - Snapshots<a href="http://fornax-sculptor.blogspot.com/2010/10/event-sourcing-with-sculptor.html">Yesterday I described</a> how events can be used as storage mechanism. Instead of storing current state we store each change as a Domain Event. Current state is reconstructed by loading and replaying all historical events. For Entities with a long life cycle it can be too many events. This can be solved with an optimization that is based on periodically storing a rolling snapshot of current state. <br /><br />Let us look at the code in the Sculptor port of the <a href="http://github.com/gregoryyoung/m-r">Simple CQRS Example</a> to understand what this means in practice. <br /><br />When loading InventoryItem we start by applying latest snapshot, if any, and thereafter replaying the events after the snapshot. This is the code in the Repository:<br /><br /><pre class="brush:java"><br /> @Override<br /> public InventoryItem findByKey(String itemId)<br /> throws InventoryItemNotFoundException {<br /> InventoryItem result = super.findByKey(itemId);<br /><br /> loadFromHistory(result);<br /><br /> return result;<br /> }<br /><br /> private void loadFromHistory(InventoryItem entity) {<br /> InventoryItemSnapshot snapshot = getInventoryItemSnapshotRepository()<br /> .getLatestSnapshot(entity.getItemId());<br /> entity.applySnapshot(snapshot);<br /> long snapshotVersion = snapshot == null ? 0 : snapshot.getVersion();<br /><br /> List<InventoryItemEvent> history = getInventoryItemEventRepository()<br /> .findAllAfter(entity.getItemId(), snapshotVersion);<br /> entity.loadFromHistory(history);<br /> }<br /></pre><br /><br /><br />That is how the snapshots are used when loading InventoryItem. Let us see how they are saved. We define the Snapshot Value Object for InventoryItem like this<br /><br /><pre class="brush:text"><br /> ValueObject InventoryItemSnapshot {<br /> String itemId index<br /> boolean activated<br /> Long version<br /> <br /> Repository InventoryItemSnapshotRepository {<br /> @InventoryItemSnapshot getLatestSnapshot(String itemId);<br /> protected findByCondition(PagingParameter pagingParameter);<br /> save;<br /> }<br /> }<br /></pre><br /><br />Here we store the state as explicit attributes, which is simple with Sculptor, since we got the persistence (to MongoDB or JPA) for free, but it can also be stored as a blob (ecoded as xml, protobuf, or whatever you prefer). In this example the only state is the activated flag, but it can be much more in a real application. <br /><br />The storage of the snapshot is triggered by a subscriber on the ordinary Domain Event flow. Simply defined as this in the model:<br /><pre class="brush:text"><br /> Service InventoryItemSnapshotter {<br /> subscribe to inventoryItemTopic<br /> inject @InventoryItemRepository<br /> inject @InventoryItemSnapshotRepository<br /> }<br /></pre><br /><br />The implementation calculates how many events has passed since previous snapshot by comparing version numbers. When the delta exceeds a threshold (e.g. 100 events) a snapshot is created and saved.<br /><pre class="brush:java"><br /> public void receive(Event event) {<br /> if (!(event instanceof InventoryItemEvent)) {<br /> return;<br /> }<br /><br /> InventoryItemEvent inventoryItemEvent = (InventoryItemEvent) event;<br /> String itemId = inventoryItemEvent.getItemId();<br /><br /> InventoryItemSnapshot snapshot = getInventoryItemSnapshotRepository()<br /> .getLatestSnapshot(itemId);<br /> long snapshotVersion = snapshot == null ? 1 : snapshot.getVersion();<br /> long eventVersion = inventoryItemEvent.getAggregateVersion() == null ? 1<br /> : inventoryItemEvent.getAggregateVersion();<br /> if (eventVersion - snapshotVersion >= VERSION_DELTA) {<br /> takeSnapshot(itemId);<br /> }<br /> }<br /><br /> private void takeSnapshot(String itemId) {<br /> InventoryItem item;<br /> try {<br /> item = getInventoryItemRepository().findByKey(itemId);<br /> } catch (InventoryItemNotFoundException e) {<br /> log.warn("takeSnapshot failed: " + e.getMessage());<br /> return;<br /> }<br /><br /> InventoryItemSnapshot snapshot = item.createSnapshot();<br /> getInventoryItemSnapshotRepository().save(snapshot);<br /> }<br /></pre><br /><br />By using snapshots we can dramatically improve performance for loading Entities with many historical changes. However, you can always start development without snapshotting and add it later, as a performance enhancement.<br /><br />Also, note that snapshots and event are immutable and therefore we have great opportunities for using caching for improving performance.<br /><br />The complete source code for this example is available here: <a href="http://github.com/patriknw/sculptor-simplecqrs/">http://github.com/patriknw/sculptor-simplecqrs/</a>Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-36736672372915611342010-10-28T14:40:00.001+02:002010-10-28T14:44:04.876+02:00Event Sourcing with SculptorA while a go Greg Young published the <a href="http://github.com/gregoryyoung/m-r">Super Simple CQRS Example</a>. There are also some good documents of how to use events as storage mechanism at the <a href="http://cqrs.wordpress.com/documents/">CQRS Info Site</a>.<br /><br />I have implemented the same example with Java and Sculptor. In this post I will describe how the Event Sourcing is implemented. Even though my implementation is facilitated by using Sculptor and MongoDB the design can easily be done with other techniques, such as JPA or plain JDBC, and without Sculptor.<br /><br />A domain model typically holds current state of the world. Event Sourcing makes it possible to see how we got to this state. Essentially it means that we have to capture all changes to an application state as a sequence of events. These events can be used to reconstruct current and past states.<br /><br />The sample application is a simplified inventory of items. In line with CQRS it has a strict separation of commands and queries. Changes to the InventoryItem domain object are published as Domain Events. The InventoryItem can be modified with a few commands that I have represented as operations in a Service.<br /><br /><pre class="brush:text"><br /> Service InventoryFacade {<br /> inject @InventoryItemRepository<br /> createInventoryItem(String itemId, String name);<br /> deactivateInventoryItem(String itemId);<br /> renameInventoryItem(String itemId, String newName);<br /> checkInItemsToInventory(String itemId, int count);<br /> removeItemsFromInventory(String itemId, int count);<br /> }<br /></pre><br /><br />All these commands are handled in the same way, except createInventoryItem, which is slightly different. The Service looks up the Entity and calls corresponding method on the domain object. <br /><pre class="brush:java"><br /> public void deactivateInventoryItem(String itemId) {<br /> InventoryItem item = tryGetItem(itemId);<br /> item.deactivate();<br /> getInventoryItemRepository().save(item);<br /> }<br /></pre><br /><br />The Entity performs validation and creates Domain Event for state changes.<br /><pre class="brush:java"><br /> public void deactivate() {<br /> if (!isActivated())<br /> throw new IllegalStateException("already deactivated");<br /> applyChange(new InventoryItemDeactivated(new Date(), getItemId()));<br /> }<br /></pre><br /><br />In this case InventoryItem has a flag (state) indicating that the item is activated or not. Note that this state is not changed directly, but it is changed later as a result of the InventoryItemDeactivated event. All changes are done with Domain Events, which is important, because we don't save current state, we only save the Domain Events. The activated flag is not stored explicitly.<br /><br />The DomainEvent is applied and added to a list of changes, which later will be stored and published.<br /><br /><pre class="brush:java"><br /> private void applyChange(InventoryItemEvent event) {<br /> applyChange(event, true);<br /> }<br /> <br /> private void applyChange(InventoryItemEvent event, boolean isNew) {<br /> DynamicMethodDispatcher.dispatch(this, event, "apply");<br /> if (isNew) {<br /> changes.add(event);<br /> } else {<br /> setVersion(event.getAggregateVersion());<br /> }<br /> }<br /><br /> public void apply(InventoryItemDeactivated event) {<br /> setActivated(false);<br /> }<br /></pre><br /><br />When saving, the InventoryItem instance is saved, but only as a key and version. The version is used for detecting concurrent modifications (optimistic locking). Additionally, the changes, the Domain Events are stored. The version number of InventoryItem is stored in Each Domain Event. An additional sequence number is also used to ensure the correct order of the events.<br /><br />We need to override the default save method in the Repository to handle these sequence numbers and also save the events.<br /><br /><pre class="brush:java"><br /> @Override<br /> public InventoryItem save(InventoryItem entity) {<br /> InventoryItem saved = super.save(entity);<br /><br /> List<InventoryItemEvent> changes = entity.getUncommittedChanges();<br /> changes = applyVersionToChanges(changes, saved.getVersion());<br /> for (InventoryItemEvent each : changes) {<br /> getInventoryItemEventRepository().save(each);<br /> }<br /> entity.markChangesAsCommitted();<br /><br /> return saved;<br /> }<br /><br /> private List<InventoryItemEvent> applyVersionToChanges(<br /> List<InventoryItemEvent> changes, long version) {<br /> List<InventoryItemEvent> result = new ArrayList<InventoryItemEvent>();<br /> long sequence = version * 1000;<br /> for (InventoryItemEvent each : changes) {<br /> result.add(each.withAggregateVersion(version).withChangeSequence(<br /> sequence));<br /> sequence++;<br /> }<br /> return result;<br /> }<br /></pre><br /><br />When saving the Domain Events they are also published to a topic, which the read side subscribes on. That is handled with the publish/subscribe mechanism in Sculptor. In the model we simply need to specifiy publish on the save method.<br /><br /><pre class="brush:text"><br /> abstract DomainEvent InventoryItemEvent {<br /> persistent<br /> String itemId index<br /> Long aggregateVersion nullable<br /> Long changeSequence nullable<br /> <br /> Repository InventoryItemEventRepository { <br /> save publish to inventoryItemTopic;<br /> List<@InventoryItemEvent> findAllForItem(String itemId);<br /> protected findByCondition;<br /> }<br /> }<br /><br /> DomainEvent InventoryItemDeactivated extends @InventoryItemEvent {<br /> }<br /></pre><br /><br />In the read side we add subscribers to this topic.<br /><pre class="brush:text"><br /> Service InventoryListView {<br /> subscribe to inventoryItemTopic<br /> inject @InventoryItemListRepository<br /> }<br /> <br /> Service InventoryItemDetailView {<br /> subscribe to inventoryItemTopic<br /> inject @InventoryItemDetailsRepository<br /> }<br /></pre><br /><br />Alright, then we are almost done. One more thing though, when retrieving a InventoryItem we must replay all events to recreate current state. We do that by overriding the default findByKey method in the Repository.<br /><br /><pre class="brush:java"><br /> @Override<br /> public InventoryItem findByKey(String itemId)<br /> throws InventoryItemNotFoundException {<br /> InventoryItem result = super.findByKey(itemId);<br /><br /> loadFromHistory(result);<br /><br /> return result;<br /> }<br /><br /> private void loadFromHistory(InventoryItem entity) {<br /> List<InventoryItemEvent> history = getInventoryItemEventRepository()<br /> .findAllForItem(entity.getItemId());<br /> entity.loadFromHistory(history);<br /> }<br /></pre><br /><br />To retrieve all events we use a simple query in the InventoryItemEventRepository.<br /><pre class="brush:java"><br /> public List<InventoryItemEvent> findAllForItem(String itemId) {<br /> List<ConditionalCriteria> criteria = criteriaFor(<br /> InventoryItemEvent.class).withProperty(itemId()).eq(itemId)<br /> .orderBy(changeSequence()).build();<br /> return findByCondition(criteria);<br /> }<br /></pre><br /><br />The loaded events are applied to the InventoryItem Domain Object.<br /><br /><pre class="brush:java"><br /> public void loadFromHistory(List<InventoryItemEvent> history) {<br /> for (InventoryItemEvent each : history) {<br /> applyChange(each, false);<br /> }<br /> }<br /><br /> private void applyChange(InventoryItemEvent event, boolean isNew) {<br /> DynamicMethodDispatcher.dispatch(this, event, "apply");<br /> if (isNew) {<br /> changes.add(event);<br /> } else {<br /> setVersion(event.getAggregateVersion());<br /> }<br /> }<br /><br /> public void apply(InventoryItemCreated event) {<br /> setActivated(true);<br /> }<br /><br /> public void apply(InventoryItemDeactivated event) {<br /> setActivated(false);<br /> }<br /><br /> public void apply(Object other) {<br /> // ignore<br /> }<br /></pre><br /><br />In this example we have used a naive approach when loading the InventoryItem by replaying all historical events. For Entities with a long life cycle it can be too many events. Then we can use a snapshot technique, which I will describe in a separate blog post.<br /><br />The complete source code for this example can be found here: <a href="http://github.com/patriknw/sculptor-simplecqrs/tree/event_sourcing_without_snapshots">http://github.com/patriknw/sculptor-simplecqrs/tree/event_sourcing_without_snapshots</a>Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com1tag:blogger.com,1999:blog-3314601722322098765.post-24894249324134747652010-10-21T17:27:00.002+02:002010-10-21T17:32:52.646+02:00Switching an existing app to MongoDBRon has switched project from using Hibernate/MySQL to MongoDB and wrote notes on the changes and gotchas. <br />Read it: <a href="http://rpstechnologies.net/ron/blog/2010/09/fornax-sculptor-dsl-tool-switching-an-existing-app-to-mongodb/">Switching an existing app to MongoDB</a>Sculptorhttp://www.blogger.com/profile/15660077990398682094noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-42070523810589483612010-09-18T09:36:00.001+02:002010-09-18T09:41:59.151+02:00Photo from San Francisco<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhueOYoj56B_yno00XrsX-u2KFLaXKoGLRqN5ALX46w8r_xDphlK-1AqsM4qh7CtxRIt_cH_w5PAD4WeHPJqTANlAA1qzRMjR2e8RC9uUb4PeHM4GnmpNxTVkBrlMENFxjQLFOgC9qJDro/s1600/DSC00928.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 69px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhueOYoj56B_yno00XrsX-u2KFLaXKoGLRqN5ALX46w8r_xDphlK-1AqsM4qh7CtxRIt_cH_w5PAD4WeHPJqTANlAA1qzRMjR2e8RC9uUb4PeHM4GnmpNxTVkBrlMENFxjQLFOgC9qJDro/s400/DSC00928.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5518155166300747586" /></a><br /><br /><a href="http://kthoms.wordpress.com/">Karsten</a> saw this in San Francisco :-)Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-50318836242077447952010-09-09T21:00:00.000+02:002010-09-09T21:08:08.075+02:00EDA CQRS Betting SampleFor todays <a href="http://jwsdsl09sep.eventbrite.com/">Xtext/Sculptor</a> seminar we have prepared a new example that illustrates some of the new event-driven features in Sculptor. It highlights a good case for using an architecture in line with <a href="http://cqrs.wordpress.com/">Command and Query Responsibility Segregation</a> (CQRS) pattern.<br /><br />Consider an online betting system. It receives a massive amount of bets. A simple model for that could be:<br /><pre class="brush:text"><br /> ValueObject Bet {<br /> String betOfferId<br /> String customerId<br /> Double amount<br /> <br /> Repository BetRepository {<br /> save;<br /> }<br /> }<br /> <br /> Service BettingEngine {<br /> inject @BetRepository<br /> <br /> placeBet(@Bet bet);<br /> }<br /></pre><br /><br />The BettingEngine process the Bet and stores the information.<br /><br />Questions pop up:<ul><br /><li>How many bets have been done by customer A?</li><br /><li>Which customers place the higest bets, on average?</li><br /><li>What are the top 10 high stakes?</li><br /></ul><br /><br />It would be rather easy to develop support for those kind of queries in the master betting engine domain, but problems will soon bubble up.<br /><br /><ul><br /><li>Poor performance - the structure of the domain model is not optimized for all types of queries.</li><br /><li>Not scalable - single centralized database will become a bottleneck.</li><br /><li>Hard to change - too much functionality in one monolithic system.</li><br /></ul><br /><br />Command-Query Responsibility Segregation (CQRS) comes to the rescue. Simplified it is about separating commands (that change the data) from the queries (that read the data). Separate subsystems take care of answering queries (reporting) and the domain for processing and storing updates can stay focused. The result of the commands are published to query subsystems, each optimized for its purpose.<br /><br />Back to the betting sample. We are aiming for a design as illustrated in next drawing. Command side on the left (green) and Query side on the right (blue).<br /> <br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2dzMdM9mTE6utEL-UzYPSiWgYqXzDez5amXhrDo6SwPMpcQGyAszFkNoNuhkYcEWjkP1pzpJ-KzjlJQYkRfTgfpQm2dPS5fhYgWSPT0MymjWNHJ00lg_sBuDRsgUUFvUfdu5eKtfi7AI/s1600/betting_demo.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 263px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2dzMdM9mTE6utEL-UzYPSiWgYqXzDez5amXhrDo6SwPMpcQGyAszFkNoNuhkYcEWjkP1pzpJ-KzjlJQYkRfTgfpQm2dPS5fhYgWSPT0MymjWNHJ00lg_sBuDRsgUUFvUfdu5eKtfi7AI/s400/betting_demo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5514625172916719714" /></a><br /><br />We publish domain events when bets are placed. There are several ways to do that in Sculptor, but one easy way is to mark a Service operation with the publish keyword in the model.<br /><pre class="brush:text"><br /> DomainEvent BetPlaced {<br /> - Bet bet<br /> }<br /><br /> Service BettingPublisher {<br /> publishEvent(@BetPlaced betEvent) publish to jms:topic:bet; <br /> }<br /></pre><br /><br />Then, in the hand-written java code simply invoke this method. In this case a one-liner in BettingEngine.<br /><br />That's all for the command side, now let us take a look at the query side. We define a new module or even better a completely new business component.<br /><br /><pre class="brush:text"><br /> Module customer {<br /> Consumer BettingConsumer {<br /> inject @CustomerStatisticsRepository<br /> subscribe to jms:topic:bet<br /> }<br /> <br /> Service BettingQueryService {<br /> getHighBetters => CustomerStatisticsRepository.findHighAverageCustomers; <br /> }<br /> <br /> Entity CustomerStatistics {<br /> gap<br /> String customerId key<br /> int numberOfBets<br /> double averageAmount index<br /> <br /> Repository CustomerStatisticsRepository { <br /> findByKey;<br /> save;<br /> List<@CustomerStatistics> findHighAverageCustomers(double limit);<br /> protected findByCondition;<br /> }<br /> }<br /> }<br /></pre><br /><br />We receive the events published from the betting engine by defining the subscribe keyword in the BettingConsumer.<br /><br />In the query side we use domain objects that are optimized for the views and reports that are needed. We denormalize the data to minimize the number of joins needed when retrieving the data. Data is calculated ahead of time. In this case we calculate the average amount for the CustomerStatistics.<br /><br />Since we are using publish/subscribe via a message bus, it might take a while until the query side is updated with the latest data, but that is not a problem. Most systems can be eventually consistent on the query side.<br /><br />The full source code for the example is available here: <a href="http://github.com/patriknw/sculptor-betting">http://github.com/patriknw/sculptor-betting</a><br /><br />In the example we have chosen MongoDB as persistence store, Camel together with ActiveMQ as event bus. It is a matter of simple configuration to use something else, such as Oracle with JPA/Hibernate and Spring Integration for the event bus. <br /><br />I was pretty impressed myself when I counted the number of lines of code that was required to implement this example. 70 lines! 40 in the model and 30 lines of hand written java code. User interface not counted.Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-89196681193725656372010-09-09T20:50:00.003+02:002010-09-09T21:07:00.791+02:00Sculptor PresentationToday we had a Sculptor presentation as part of the seminar 'Developing Domain-Specific Languages with Xtext'. The slides from this presentation is available at slideshare: <a href="http://www.slideshare.net/patriknw/sculptor">http://www.slideshare.net/patriknw/sculptor</a>Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-27380361583177300002010-09-02T08:28:00.003+02:002010-09-02T08:38:27.251+02:00Free Seminar: Developing DSLs with XtextNext Thursday, September 09, in Stockholm, we will talk about Sculptor in the context of how to develop textual Domain-Specific Languages with Xtext. In this talk Sven Efftinge, original creator of Xtext, will present Xtext. I'm looking forward to listen to Sven's presentation.<br /><br />More information and registration here: <a href="http://jwsdsl09sep.eventbrite.com/">http://jwsdsl09sep.eventbrite.com/</a>Sculptorhttp://www.blogger.com/profile/15660077990398682094noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-36084731731182705072010-08-26T10:00:00.001+02:002010-08-26T10:11:34.614+02:00EDA Akka as EventBusSome time since <a href="http://fornax-sculptor.blogspot.com/2010/08/eda-events-over-system-boundaries-with.html">last entry</a> in the EDA-sequence, but here we are again. Today we are going to do something really interesting. A friend and colleague of us, <a href="http://jonasboner.com/">Jonas Bonér</a>, is the creator of a super interesting framework called <a href="http://akkasource.org/">Akka</a>.<br />Akka is an event driven platform for constructing highly scalable and fault tolerant applications. It is built with <a href="http://www.scala-lang.org/">Scala</a>, but also have a rich API for java. It follows the <a href="http://en.wikipedia.org/wiki/Actor_model">Actor Model</a> and together with <a href="http://en.wikipedia.org/wiki/Software_transactional_memory">Software Transactional Memory</a> (STM), it raises the abstraction level and provides an easy to use tool for building highly concurrent applications.<div>So, today we are going to take advantage of the java API in Akka to do our own EventBus implementation.</div><div><br /></div><div>First, update your pom with the stuff needed for Akka (repo's and dependency):</div><pre class="brush:xml"><repository><br /><id>Akka</id><br /><name>Akka Maven2 Repository</name><br /><url>http://www.scalablesolutions.se/akka/repository/ </url><br /></repository><br /><br /><repository><br /><id>Multiverse</id><br /><name>Multiverse Maven2 Repository</name><br /><url>http://multiverse.googlecode.com/svn/maven-repository/releases/</url><br /></repository><br /><br /><repository><br /><id>GuiceyFruit</id><br /><name>GuiceyFruit Maven2 Repository</name><br /><url>http://guiceyfruit.googlecode.com/svn/repo/releases/ </url><br /></repository><br /><br /><repository><br /><id>JBoss</id><br /><name>JBoss Maven2 Repository</name><br /><url>https://repository.jboss.org/nexus/content/groups/public/ </url><br /></repository><br /><br />...<br /><br /><dependency><br /><groupId>se.scalablesolutions.akka</groupId><br /><artifactId>akka-core_2.8.0</artifactId><br /><version>0.10</version><br /></dependency><br /></pre><br /><br /><div>Second, create your implementation of the bus, AkkaEventBus.java:</div><br /><pre class="brush:java"><br />package org.foo;<br /><br />import org.fornax.cartridges.sculptor.framework.event.Event;<br />import org.fornax.cartridges.sculptor.framework.event.EventBus;<br />import org.fornax.cartridges.sculptor.framework.event.EventSubscriber;<br /><br />import se.scalablesolutions.akka.actor.ActorRef;<br />import se.scalablesolutions.akka.actor.ActorRegistry;<br />import se.scalablesolutions.akka.actor.UntypedActor;<br />import se.scalablesolutions.akka.actor.UntypedActorFactory;<br /><br />public class AkkaEventBus implements EventBus {<br /><br /> public boolean subscribe(final String topic, final EventSubscriber subscriber) {<br /> UntypedActor.actorOf(new UntypedActorFactory() {<br /> public UntypedActor create() {<br /> return new ActorListener(topic, subscriber);<br /> }<br /> }).start();<br /> <br /> return true;<br /> }<br /><br /> public boolean unsubscribe(String topic, EventSubscriber subscriber) {<br /> // TODO : implement mapping between arbitrary subscriber and actor in registry<br /> return true;<br /> }<br /><br /> public boolean publish(String topic, Event event) {<br /> ActorRef[] actorsForTopic = ActorRegistry.actorsFor(topic);<br /> for (int i = 0; i < actorsForTopic.length; i++) {<br /> actorsForTopic[i].sendOneWay(event);<br /> }<br /> return true;<br /> }<br /><br /> @SuppressWarnings("unchecked")<br /> private class ActorListener extends UntypedActor {<br /> final String topic;<br /> final EventSubscriber subscriber;<br /><br /> ActorListener(String topic, EventSubscriber subscriber) {<br /> this.topic = topic;<br /> this.subscriber = subscriber;<br /> this.getContext().setId(topic);<br /> }<br /><br /> @Override<br /> public void onReceive(Object message) throws Exception {<br /> this.subscriber.receive((Event) message);<br /> }<br /> <br /> }<br />}<br /><br /></pre><div>As you can see, I lack the unsubscribe implementation and I left out equals and hashCode overrides, but that I leave to you.</div><div>Third, add it as our bus implementation through spring config:</div><br /><pre class="brush:xml"><br /><bean id="akkaEventBus" class="org.foo.AkkaEventBus"/><br /><alias name="akkaEventBus" alias="eventBus"/><br /></pre><br /><br /><div>What we have done now is built an highly scalable and concurrent EventBus that dispatches event asynchronously.</div><div>Pretty easy, right? :-)</div><div><br /></div><div>It doesn't run over the network, but Akka has some nice modules for that as well, so that is our task for next time.</div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-91112505433199739452010-08-11T18:07:00.000+02:002010-08-11T18:59:10.799+02:00EDA events over system boundaries - with camel<a href="http://fornax-sculptor.blogspot.com/2010/08/eda-events-over-system-boundaries.html">Last time</a> we examined how we could make our events travel over system boundaries with the help of <a href="http://en.wikipedia.org/wiki/Java_Message_Service">JMS</a> and <a href="http://www.springsource.org/spring-integration">Spring-integration</a>.<div>Today we will do exactly the same but we will use Apache Camel as event engine instead. The task is to enable application domain events over system boundaries through JMS. If you don't remember our model, here it is again:</div><pre class="brush:java">Application Universe {<br />basePackage=org.helloworld<br /><br />Module milkyway {<br /> Service PlanetService {<br /> @BigLandingSuccess landOnPlanet(String planetName, String astronautName)<br /> publish to milkywayChannel;<br /> }<br /><br /> DomainEvent BigLandingSuccess {<br /> String planetName<br /> String astronautName<br /> }<br />}<br />Module houston {<br /> Service GroundControlService {<br /> subscribe to milkywayChannel<br /> bringOutTheChampagne(int noOfBottles);<br /> }<br />}<br />}</pre><div>To use Apache Camel as event engine, you need to specify it in the sculptor-generator.properties file:</div><div><span class="Apple-style-span" style=" color: rgb(51, 51, 51); line-height: 16px; "><span class="Apple-style-span" style="font-size:medium;">integration.product=camel</span></span></div><div>And add the needed dependencies to the projects pom-file:</div><pre class="brush:xml"><br /><dependency><br /><groupId>org.apache.camel</groupId><br /><artifactId>camel-core</artifactId><br /><version>2.3.0</version><br /></dependency><br /><dependency><br /><groupId>org.apache.camel</groupId><br /><artifactId>camel-jms</artifactId><br /><version>2.3.0</version><br /></dependency><br /><dependency><br /><groupId>org.apache.camel</groupId><br /><artifactId>camel-spring</artifactId><br /><version>2.3.0</version><br /></dependency><br /><dependency><br /><groupId>org.apache.activemq</groupId><br /><artifactId>activemq-camel</artifactId><br /><version>5.3.2</version><br /></dependency><br /><!-- xbean is required for ActiveMQ broker configuration in the spring xml file --><br /><dependency><br /><groupId>org.apache.xbean</groupId><br /><artifactId>xbean-spring</artifactId><br /><version>3.7</version><br /></dependency><br /><dependency><br /><groupId>javax.xml.bind</groupId><br /><artifactId>jaxb-api</artifactId><br /><version>2.1</version><br /></dependency><br /></pre><div>Regenerate and you will have a new camel.xml file in src/main/resources. This file is only generated once, and you can use it to add configuration for Camel.<br /></div><div>To do the same as we did with spring-integration, i.e. put a domain event on a jms topic, we just have to add route rule to the camel.xml file:</div><pre class="brush:xml"><br /><camel:route><br /> <camel:from uri="direct:shippingChannel"/><br /> <camel:to uri="jms:topic:shippingEvent"/><br /></camel:route><br /></pre><br />And that's it. Now we are publishing our domain event to an ActiveMQ topic. Yes, a bit strange that it works, but it gets clearer if we look in camel.xml and see whats was already there:<br /><pre class="brush:xml"><br /><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:broker="http://activemq.apache.org/schema/core" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd"><br /><bean id="camelEventBusImpl" class="org.fornax.cartridges.sculptor.framework.event.CamelEventBusImpl"/><br /><alias name="camelEventBusImpl" alias="eventBus"/><br /><br /><camel:camelContext id="camel"><br /> <camel:package>org.sculptor.shipping</camel:package><br /> <camel:template id="producerTemplate"/><br /></camel:camelContext><br /><!--<br /> Camel ActiveMQ to use the ActiveMQ broker<br /> --><br /><bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent"><br /> <property name="brokerURL" value="tcp://localhost:61616"/><br /></bean><br /></beans><br /></pre><br />We have a bean that wires the jms api's to the actual ActiveMQ instance together. So you have to have an ActiveMQ instance up and running listening on port 61616.<div><br /></div><div>All for today, next time...we'll see what the subject is...</div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-45536907740957412302010-08-02T22:00:00.001+02:002010-08-02T22:00:01.209+02:00EDA events over system boundariesIn the last <a href="http://fornax-sculptor.blogspot.com/2010/07/eda-why-event-bus-in-sculptor.html">post</a> we explained why we have the 'event bus' notion. And earlier we have seen how to use it to publish and subscribe, both through the dsl in the model, or through plain java code.<div>Today we thought we should look how you can make domain events part of the public api of your business component and publish them to the rest of the world.</div><div>To do this we will use the event bus implementation that is based on spring integration. We will use its <a href="http://static.springsource.org/spring-integration/reference/htmlsingle/spring-integration-reference.html#jms-outbound-channel-adapter">JMS outbound channel adapter</a> to publish the 'BigLandingSuccess' domain event to a jms topic that the rest of the world can listen to.</div><div>If you don't remember, here is the model:</div><br /><pre class="brush:java">Application Universe {<br /> basePackage=org.helloworld<br /><br /> Module milkyway {<br /> Service PlanetService {<br /> @BigLandingSuccess landOnPlanet(String planetName, String astronautName)<br /> publish to milkywayChannel;<br /> }<br /><br /> DomainEvent BigLandingSuccess {<br /> String planetName<br /> String astronautName<br /> }<br /> }<br /> Module houston {<br /> Service GroundControlService {<br /> subscribe to milkywayChannel<br /> bringOutTheChampagne(int noOfBottles);<br /> }<br /> }<br />}</pre><br /><div>But first, how do we replace the default event bus implementation with the spring-integration based?</div><div>In <span class="Apple-style-span" style="font-family:'courier new';">sculptor-generator.properties</span>, add the property:</div><div><span class="Apple-style-span" style="font-family:'courier new';">integration.product=spring-integration</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><br /></span></div><div>And in the project pom file, add the dependency:</div><pre class="brush:xml"><dependency><br /> <groupId>org.springframework.integration</groupId><br /> <artifactId>org.springframework.integration</artifactId><br /> <version>1.0.4.RELEASE</version><br /></dependency></pre><div>Regenerate, and you are home. So, now all event routing will use spring-integration as engine. So without any other changes, it works exactly as before.<br />Now you have to decide how your public api should look like, and in our case we decides that the 'BigLandingSuccess' domain event should be made available for other applications to listen to.</div><div>And now we take advantage of the power of spring-integration. When we regenerated with spring-integration enabled, we ended up with the file:<br /><span class="Apple-style-span" style="font-family:'courier new';">src/main/resources/spring-integration.xml</span></div><div>This is the place where all spring-integration definitions lands. It is generated once, so you are now free to edit it. Open the file and add:</div><pre class="brush:xml"><jms:outbound-channel-adapter id="publicMilkywayChannel" destination="publicMilkywayTopic" channel="milkywayChannel"/></pre><div>You will need a <a href="http://static.springsource.org/spring/docs/2.5.x/reference/jms.html">spring jms bean</a> named 'publicMilkywayTopic' and that bean needs to map to an actual message broker instance, for example <a href="http://activemq.apache.org/">ActiveMQ</a>. But the spring bean and message broker setup is out scope for this blog entry, so that one we leave to you. </div><div>The only caveat now is that we are exposing our java objects in the message. This can be cured with a transformation step before the jms adapter. So add a transformer to your spring-integration configuration:</div><pre class="brush:xml"><object-to-string-transformer input-channel="milkywayChannel" output-channel="milkywayMessagesAsStringChannel"/><br /></pre>And change the jms outbound channel to wire up with the new channel:<pre class="brush:xml"><jms:outbound-channel-adapter id="publicMilkywayChannel" destination="publicMilkywayTopic" channel="milkywayMessagesAsStringChannel"/><br /></pre>Spring-integration has a lot of transformers you can use. The above just transforms a java object to a string through its toString method. That is of course not always what you want, but it works for this example.<div><br /><div>So that was all that had to be done to make a domain event part of your public api. Of course, you need to have proper documentation to give others a fair chance of finding your event.</div><div><br /></div><div>If we take one step back and consider what we have done.<br />First, we declared the 'BigLandingSuccess' domain event and publishes it internally.</div><div>Second, we add an adapter that listens to the channel and in its turn publishes it on a jms topic, i.e. makes it public.</div><div>Third, we added a transformation step before doing a public publish to remove the dependency to our classes.</div><div><br /></div>Now, this is nice, isn't it? We can have a lot of domain events internally in our application and by that take advantage of all the nice attributes of EDA. And we can by choice make a domain event public with 'just' configuration changes.<div><br /></div><div>Quite long post, but we got pretty much done. Next time we will look how to do the same with Apache Camel</div></div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-91862781117280159422010-08-01T15:26:00.000+02:002010-08-02T00:26:50.538+02:00EDA why the event bus in sculptor?We have come to our seventh entry about <a href="http://en.wikipedia.org/wiki/Event-driven_architecture">Event Driven Architecture</a>. We are in the topic of how Sculptor supports EDA. In previous posts we have covered how to publish and subscribe, both through the dsl in the model, and through plain java code.<div>Today we will talk a bit more on the thin layer we call 'the event bus'.</div><div><br /></div><div>As stated before, there are a lot of different approaches to EDA. You can use/implement it locally or apply it too the entire enterprise. But also, in its simplest form its about the observer pattern, regardless if we talk about big or small implementations. This leads us to the main motivations of our event bus abstraction.</div><div>We want to keep it simple, but at the same time still have the power of doing event handling big and small. In the Enterprise, or locally. And doing this with the same programming interfaces, i.e. keeping it simple.</div><div>So, based on the above we have the event bus api. And with the risk of repeating my self, it is a very simple one. Methods for publishing, subscribing, and un-subscribing.</div><div><br /></div><div>It also ships with a default implementation named (you got it) simple event bus. This one is really easy (hey, I found another word instead of simple) to use and fully functional on its own. Though, if you need to integrate with another system you are going to need another implementation. </div><div>And that is one of our other motivation for the event bus, it should be easy to swap implementations.</div><div>Beside the default, we currently have two implementations based on <a href="http://www.springsource.org/spring-integration">Spring-integration</a> and <a href="http://camel.apache.org/">Apache Camel</a>. Both of these are what's called "lightweight integration frameworks". Supporting these two frameworks brings a lot of power to the solution when it comes to integration.</div><div>And that brings us to the next topic of this series. Some examples of how to bring your events to life over system boundaries, i.e. integration stuff.</div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-32867598057360845082010-07-30T15:01:00.001+02:002010-07-30T15:24:03.707+02:00EDA pub/sub with plain javaIn a couple of posts we have seen how to <a href="http://fornax-sculptor.blogspot.com/2010/07/eda-simple-example-with-sculptor.html">publish</a> and <a href="http://fornax-sculptor.blogspot.com/2010/07/eda-simple-example-with-sculptor_29.html">subscribe</a> to events. I showed how to do that through the dsl in the model. But you have of course also the possibility to do pub/sub by plain java code as well. The key thing is to have a handle to the event bus.<div>The easiest way to explain it is to show an example, so, a simple service that publish an event as part of it's business logic:</div><br /><pre class="brush:java"><br />@Service<br />public class GroundControlService {<br /><br /> @Autowired<br /> @Qualifier("eventBus")<br /> private EventBus eventBus;<br /><br /> @Override<br /> public void receive(Event event) {<br /> if (event instanceof BigLandingSuccess) {<br /> eventBus.publish("earthChannel", new Celebration("We did it!"));<br /> this.bringOutTheChampagne(ALL);<br /> eventBus.publish("supplierChannel", new MissingResource("Champagne"));<br /> }<br /> }<br />}<br /></pre>And for the other end, the subscriber:<br /><pre class="brush:java"><br />@Service<br />public class SupplierService {<br /><br />@Autowired<br />@Qualifier("eventBus")<br />private EventBus eventBus;<br /><br />public void init() {<br /> eventBus.subscribe("supplierChannel", new EventSubscriber() {<br /> @Override<br /> public void receive(Event event) {<br /> if (event instanceof MissingResource) {<br /> raceForContract(event);<br /> }<br /> }<br /> });<br />}<br />}<br /></pre><br /><div>Not so hard.</div><div>Now, here and there I've used the term 'event bus', and you have also seen it in java code above. Next time we will look closer into the bus. Why is there an abstraction and what can you do with it?</div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-60531800843895904262010-07-29T14:45:00.004+02:002010-07-29T15:17:12.498+02:00EDA a simple example with Sculptor continuedLets continue with our simple example from the last <a href="http://fornax-sculptor.blogspot.com/2010/07/eda-simple-example-with-sculptor.html">post</a>. We declared a domain event in the model and we marked a service to publish that event to a channel.<div>Now, what about getting notified when such an event is published?</div><div><br /></div><div>Continuing with our model from last time, its just a matter of editing it. Lets create another module with a service that is interested of the event:</div><br /><pre class="brush:java">Application Universe {<br /> basePackage=org.helloworld<br /><br /> Module milkyway {<br /> Service PlanetService {<br /> @BigLandingSuccess landOnPlanet(String planetName, String astronautName)<br /> publish to milkywayChannel;<br /> }<br /><br /> DomainEvent BigLandingSuccess {<br /> String planetName<br /> String astronautName<br /> }<br /> }<br /> Module houston {<br /> Service GroundControlService {<br /> subscribe to milkywayChannel<br /> bringOutTheChampagne(int noOfBottles);<br /> }<br /> }<br />}</pre><div><br />The result is that the GroundControl service will implement the EventSubscriber interface and be marked with @Subscribe annotation. That means that the GroundControl service will automatically be added as subscriber to milkywayChannel. It will be notified, receive method called, when events are published to that channel.<br /></div><div>You will get a stub of the receive method of the EventSubscriber interface.<br /></div><br /><pre class="brush:java"><br />@Override<br />public void receive(Event event) {<br /> // TODO Auto-generated method stub<br /> throw new UnsupportedOperationException("receive not implemented");<br />}<br /></pre><br /><div>So that you will need to implement with your logic:</div><br /><pre class="brush:java"><br />@Override<br />public void receive(Event event) {<br /> if (event instanceof BigLandingSuccess) {<br /> this.bringOutTheChampagne(999999);<br /> }<br />}<br /></pre><div>Ok, so now we covered some very simple notations for publishing and subscribing to events. Next time I'll show how to do the same but in plain java code.<br /></div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-54898814568279948392010-07-26T18:00:00.003+02:002010-07-26T23:33:26.100+02:00EDA a simple example with SculptorNow we have gone through EDA in general, and briefly covered how we support it in Sculptor. It's time to see how it can be used.<div>We start with a simple example where we will show how to declare a domain event and how that event is published. </div><div>Let us use our old, well known, hello world example.</div><pre class="brush:java"><br />Application Universe {<br />basePackage=org.helloworld<br /><br />Module milkyway {<br /> Service PlanetService {<br /> void landOnPlanet(String planetName, String astronautName);<br /> }<br /><br />}<br />}<br /></pre>That is our model. So, what might the rest of the 'universe' be interested of here? Well, if NASA sent out a space ship with an astronaut on it who's mission was to land on some far far away planet, wouldn't they be interested in the event of a landing? I think so. So, when a astronaut lands on a planet, we would like the service to publish an event of this happening.<div>Lets start with re-defining the model with the event:</div><pre class="brush:java">Application Universe {<br />basePackage=org.helloworld<br /><br />Module milkyway {<br /> Service PlanetService {<br /> void landOnPlanet(String planetName, String astronautName);<br /> }<br /><br /> DomainEvent BigLandingSuccess {<br /> String planetName<br /> String astronautName<br /> }<br />}<br />}<br /></pre><br /><div>DomainEvents may contain attributes and references in the same way as ValueObjects and Entities. DomainEvents are always immutable and not persistent.<br /><br />Events are about something happening at a point in time, so it's natural for events to contain time information. Sculptor automatically adds two timestamps, occurred and recorded. The time the event occurred in the world and the time the event was noticed.</div><div><br /></div><div>Ok, so now we have the event defined, now we want it to be published. The easiest way of doing this is to mark the service in the dsl (you can of course publish events programmatically, but more about that in a later blog entry) . So, once again, lets re-define our model:</div><br /><pre class="brush:java">Application Universe {<br />basePackage=org.helloworld<br /><br />Module milkyway {<br /> Service PlanetService {<br /> @BigLandingSuccess landOnPlanet(String planetName, String astronautName)<br /> publish to milkywayChannel;<br /> }<br /><br /> DomainEvent BigLandingSuccess {<br /> String planetName<br /> String astronautName<br /> }<br />}<br />}</pre><div>The operation must return a DomainEvent or take a DomainEvent as parameter. That event is published to the defined channel when the operation has been invoked.<br /><br />As an alternative the DomainEvent instance can be created from the return value or parameters. The DomainEvent must have a matching constructor.<br /></div><div><br />The result of the above declarative way of publishing events is a generated annotation @Publish on the method. It will trigger the Spring AOP advice PublishAdvice that is part of Sculptor framework.<br /></div><div><br /></div><div>Recap: We have declared an event in our model, and further marked our service to publish this event when it happens. As an API, I think this is very neat. Everyone who is interested can see that when an astronaut lands on a planet, he or she can be notified. </div><div>And that is what we will talk about next time:</div><div><br /></div><div>How can I be notified when things happens?</div><div><br /></div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-10908540707253648002010-07-19T18:00:00.000+02:002010-07-19T21:50:07.103+02:00EDA sculptor support<div>In the previous <a href="http://fornax-sculptor.blogspot.com/2010/07/eda-overview.html">post</a> we gave an overview of <a href="http://en.wikipedia.org/wiki/Event-driven_architecture">Event Driven Architecture</a>. It is a very big area, and you can use it to a lot of things.<br />It is a very good complement to DDD, and is a corner stone when building scalable systems.<br />When constructing systems it is a very nice match to accomplish loosely coupled modules and bounded contexts, i.e. business components. And much more.<br /><br />We strive for simplicity, but at the same time not restricting us.<br /><br />So, how can you use with Sculptor?<br />In the 1.9.0 release, we have focused on support for <a href="http://en.wikipedia.org/wiki/Publish/subscribe">Publish/Subscribe</a>, <a href="http://www.udidahan.com/2009/12/09/clarified-cqrs/">Comman-Query Responisbility Segregation (CQRS)</a> and <a href="http://martinfowler.com/eaaDev/EventSourcing.html">Event Sourcing. </a><br /><br />The most useful part is of course the pub/sub support. Event sourcing is an architectural style that has its niche. CQRS is also an architectural style that there has been some publicity around lately. CQRS uses pub/sub and can with advantage be constructed to use Event Sourcing.<br /><br />To support the above, there are three central parts in our implementation:<br /><ul><li>An event bus abstraction</li><li>DomainEvent</li><li>CommandEvent</li></ul><span style="font-weight: bold;">"The bus"</span><br />The event bus is an extremely simple API, with three different implementations (in 1.9.0), "Simple", <a href="http://www.springsource.org/spring-integration">Spring Integration</a> and <a href="http://camel.apache.org/">Apache Camel</a>. The idea is that the central parts, i.e. pub/sub, should be easy to use. The only thing you have to work with is an event bus where you publish and subscribes to and from events. And if you need some non functional behavior (asynchronism, over the wire, etc) for your events, you plug in an event bus that can handle this requirements.<br />And as stated above, the easiest way to accomplish that with the 1.9.0 release is to use Spring Integration or Apache Camel. But you can also choose to implement your own event bus.<br />You can publish and subscribe to and from the bus either declarative through the DSL, or programatically through the event bus API.<br /><br /><span style="font-weight: bold;">DomainEvent vs CommandEvent</span> </div><div><div>CommandEvent is an instruction for something to happen. The system processes a CommandEvent and takes appropriate actions.</div><div><br /></div><div>DomainEvent states fact - that something has happen. This fact is published to the rest of the world and the publisher just lets it go with no further interest in what happens to the event, i.e. who receives it and what they do.<br /><br />If you compare it to an application API, CommandEvent could be the input API, while the DomainEvent is the output API for the application. I.e. the CommandEvent is what you can make the application perform, while the DomainEvent is what the application reports has happen.<br /><br />As you probably figured out, CommandEvent is for implementing CQRS and Event Sourcing.<br /><br />Finally, let us take quick look at how the notion for DomainEvents look like in the DSL.<br /><pre class="code-java">DomainEvent ShipHasArrived {<br /> - ShipId ship<br /> - UnLocode port<br />}<br /> <br />DomainEvent ShipHasDepartured {<br /> - ShipId ship<br /> - UnLocode port<br />}<br /></pre>As you can see, you define a domain event in the same way as for entities or value objects.<br /><br />And to declare pub/sub:<br /><pre class="code-java">Service TrackingService {<br /> @ShipHasArrived recordArrival(DateTime occurred, @Ship ship, @Port port)<br /> publish to shippingChannel;<br />}<br />Service Statistics {<br /> subscribe to shippingChannel<br /> <span class="code-object">int</span> getShipsInPort(@UnLocode port);<br /> reset;<br />}<br /><br /><br /><span style="font-size:130%;"><span style="font-family:georgia;">That was all for today, next time will it be more concrete with examples of how to use it.</span></span><br /><br /></pre><br /></div></div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-86016698267830661992010-07-15T18:00:00.004+02:002010-07-15T20:56:39.688+02:00EDA overview<div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">As stated in the </span></span><a href="http://fornax-sculptor.blogspot.com/2010/07/eda-intro.html"><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">last post</span></span></a><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">, we would like to talk a bit (very shortly) about EDA in a broader sense to give an overview of it and to give you a sense for what we read into the term EDA. This is quite important as a background when we go further and explain our interpretation and implementation of it.</span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;"><br /></span></span></div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">Event Driven Architecture is a very broad area. But in a short sentence its about:</span></span><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">Applications and systems that produce, consume and reacts on events.</span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;"><br /></span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">And even if there is a lot of attention on EDA as means of implementing integration between applications and systems, EDA can be applied within applications and even in parts of applications.</span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;"><br /></span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">The benefits of an EDA is:</span></span></div><div><ul><li><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">loosely coupled systems (or internals of a system) </span></span></li><li><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">high performance (fire and forget)</span></span></li><li><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">high scalability</span></span></li></ul><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">Of course this comes with a trade-off. An extra abstraction is added, i.e. it becomes more complex.</span></span></div></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;"><br /></span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">In it's simplest form, EDA is about the </span></span><a href="http://en.wikipedia.org/wiki/Observer_pattern"><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">Observer Pattern</span></span></a><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">. Something happens somewhere, and 0 to n parties is interested in that happening. From this simple pattern, all interpretations, implementations and usages of EDA are spawn.</span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;"><br /></span></span></div><div><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">So, before we go into how we have implemented support for EDA in Sculptor, we will give you some examples of what shapes we think EDA can take. Big and small...here we go:</span></span><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">GUI's</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">Swing uses the Observer pattern. Many different GUI frameworks uses an event driven approach. Java Server Faces works with events, event handlers and event actions. Etc...</span></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">DomainEvent</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">A </span><a href="http://martinfowler.com/eaaDev/DomainEvent.html"><span class="Apple-style-span" style="font-family:verdana;">Domain Event</span></a><span class="Apple-style-span" style="font-family:verdana;"> is registration of something that has happen. It might be of interest to 0 to n consumers. The thing is; The producer doesn't care, it just tell the world that this thing has happen and happily goes on with it's life. </span></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">PubSub</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">Publisher and Subscribers is a central part of all event driven integrations. It is an implementation of the Observer pattern. It often comes with persistent events. Topics in the Java/JMS tech domain is an implementation of it.</span></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">SOA2.0</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">Now when SOA has been around for some years the next thing is SOA2.0. In the 2.0 version of SOA events plays a central role as a complement to services.</span></div><div><span class="Apple-style-span" style=" line-height: 19px; "><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;"> An event-driven system typically consists of event emitters (or agents) and event consumers (or sinks). Sinks have the responsibility of applying a reaction as soon as an event is presented. The reaction might or might not be completely provided by the sink itself. For instance, the sink might just have the responsibility to filter, transform and forward the event to another component or it might provide a self contained reaction to such event. The first category of sinks can be based upon traditional components such as message oriented middleware while the second category of sinks (self contained online reaction) might require a more appropriate transactional executive framework, for example an ESB.</span></span></span></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">Event servers</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">Event servers are servers that are specialized in processing events. They often provide filter/query capabilities for events. </span><a href="http://download-llnw.oracle.com/docs/cd/E13213_01/wlevs/docs20/"><span class="Apple-style-span" style="font-family:verdana;">Weblogic Event Server</span></a><span class="Apple-style-span" style="font-family:verdana;"> is an example of this kind of product.</span></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">Event sourcing</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">All changes to an application is recorded as a series of events. An applications current state can be queried. But not only that, an application state can be rolled forward or backwards as you wish, giving you a lot of power. </span><a href="http://martinfowler.com/"><span class="Apple-style-span" style="font-family:verdana;">Martin Fowler</span></a><span class="Apple-style-span" style="font-family:verdana;"> has written all about it </span><a href="http://martinfowler.com/eaaDev/EventSourcing.html"><span class="Apple-style-span" style="font-family:verdana;">here</span></a><span class="Apple-style-span" style="font-family:verdana;">. Also, Patrik has written a couple of blog entries of how he has played with it and now also added support for it in Sculptor, see </span><a href="http://fornax-sculptor.blogspot.com/2010/05/prototyping-event-sourcing.html"><span class="Apple-style-span" style="font-family:verdana;">here</span></a><span class="Apple-style-span" style="font-family:verdana;"> and </span><a href="http://fornax-sculptor.blogspot.com/2010/06/event-sourcing-snapshots.html"><span class="Apple-style-span" style="font-family:verdana;">here</span></a><span class="Apple-style-span" style="font-family:verdana;">.</span></div></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><b><span class="Apple-style-span" style="font-family:verdana;">CQRS</span></b></div><div><span class="Apple-style-span" style="font-family:verdana;">Command and Query Responsibility Segregation is a very cool area. I will not try to explain it in detail, it is very well done </span><a href="http://www.udidahan.com/2009/12/09/clarified-cqrs/"><span class="Apple-style-span" style="font-family:verdana;">here</span></a><span class="Apple-style-span" style="font-family:verdana;">.</span></div><div><span class="Apple-style-span" style="border-collapse: collapse; line-height: 16px; "><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:verdana;">Simplified it is about separating commands (that change the data) from the queries (that read the data). Separate subsystems take care of answering queries (reporting) and the domain for processing and storing updates can stay focused. The result of the commands are published to query subsystems, each optimized for its purpose.</span></span></span></div><div><span class="Apple-style-span" style=" border-collapse: collapse; line-height: 16px; font-size:11px;"><span class="Apple-style-span" style="font-family:verdana;"><br /></span></span></div><div><span class="Apple-style-span" style="font-family:verdana;">Ok, that was probably a very short and incomplete list of EDA related topics, but it gave you a taste for it and a ground for further reading. We will use it as a foundation when we talk about how we think about and implements EDA. </span></div><div><span class="Apple-style-span" style="font-family:verdana;">If you think we have missed an important topic, tool, concept, etc, around EDA, please add a comment about it.</span></div><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><span class="Apple-style-span" style="font-family:verdana;">Next up, how we support EDA in Sculptor.</span></div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-28646368387062298782010-07-12T18:00:00.002+02:002010-07-12T19:07:18.924+02:00EDA introBoth Patrik and I have always been believers of Event Driven Architecture. EDA has been around for many years, but recently the attention towards it has increased. The reasons for that is probably many, but I guess one of the most important is that EDA will help you build more concurrent and scalable system.<div>Therefore, as we strive to support popular technologies, we take the opportunity to implement support for EDA in the newly <a href="http://fornax.itemis.de/confluence/display/fornax/0.+What's+New+(CSC)#0.What%27sNew%28CSC%29-v19">released 1.9.0 version</a> of Sculptor.<br /><br />Patrik has written a couple of interesting posts (<a href="http://fornax-sculptor.blogspot.com/2010/05/prototyping-event-sourcing.html">here</a> and <a href="http://fornax-sculptor.blogspot.com/2010/06/event-sourcing-snapshots.html">here</a>) about event driven architecture in a special implementation model, <a href="http://martinfowler.com/eaaDev/EventSourcing.html">event sourcing</a>.<br />Event sourcing is a powerful tool in certain circumstances. Though, not always a perfect match.</div><div>Also, many people reads <a href="http://en.wikipedia.org/wiki/Event-driven_SOA#SOA_2.0">SOA2.0</a> or <a href="http://en.wikipedia.org/wiki/Enterprise_service_bus">ESB</a> when you say EDA. This is for sure true in many cases, but just a small set of the truth. </div><div>EDA is much more than event sourcing, SOA2.0 or ESB implementations.</div><div>EDA plays a big role in application architecture and design (or even module design) as well.</div><div><br /></div><div>Our approach is that you as a developer should be able to choose how and where you implement EDA.<br /><br /></div><div>That is what we will talk about in a sequence of posts.</div><div>EDA in general. </div><div>EDA, how we see it. </div><div>EDA, how we support it.<br /><br /></div><div>So, stay tuned for more about EDA.</div>Andreashttp://www.blogger.com/profile/08618614943051927546noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-1082613843478169222010-07-11T20:25:00.000+02:002010-07-11T20:27:27.177+02:00What's Next, after 1.9.0Next release will mostly be a technical upgrade. <a href="http://www.eclipse.org/Xtext/">Xtext</a> and <a href="http://wiki.eclipse.org/Xpand">Xpand</a> version 1.0 were released together with Eclipse Helios. We will upgrade to that.<br /><br />Spring 3.0 and JPA 2.0 are also important upgrades.<br /><br />Oliver will contribute with more cool stuff. He has some almost finished things that he will share with us (hopefully) soon. <br /><br />The original design of Sculptor has worked fine and we will not change it, but 3 years of additions of different combinations of target implementations is starting to hurt some templates. Therefore we will remove some old (probably unused) target implementations. Those have been deprecated in 1.9.0 and in case you are using any of it you should start migration to some of the more modern alternatives:<br /><ul><br /><li>EJB/Spring combination => migrate to EJB3 or Spring </li><br /><li>EJB 2 => migrate to EJB3 or Spring </li><br /><li>Hibernate mapping with XML => migrate to JPA/Hibernate with annotations </li><br /><li>Spring definitions in XML => migrate to Spring with annotations </li><br /><li>Hibernate without JPA => migrate to JPA/Hibernate</li><br /></ul><br />This makes a good reason to use version number 2.0.0 for next release. Personally I get bad vibrations when Open Source project go to 2.0. That often means total redesign and no backwards compatibility. That will not be the case for Sculptor 2.0. It will be a cleanup, and some pieces are not supported any more, but most of it will stay intact and be compatible (with some migration steps, as usual).Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-47012891286932539552010-07-11T20:15:00.000+02:002010-07-11T20:25:07.528+02:00Exploring new features in 1.9.0This post is dedicated for those of you who are already using Sculptor and would like to have a quick overview of some selected features in the release. I will not bring up bug fixes and all improvements. Please refer to the complete list in <a href="http://fornax.itemis.de/jira/secure/IssueNavigator.jspa?reset=true&pid=10050&fixfor=10320">issue tracker</a> for that. <br /><br />I have written a separate <a href="http://fornax-sculptor.blogspot.com/2010/07/sculptor-190-support-for-mongodb-and.html">teaser about the MongoDB and EDA</a> features of the new release.<br /><br /><span style="font-weight:bold;">Generated Documentation</span><br /><br />In the model you can write documentation as a quoted string in front of almost every element (attribute, reference, entity, operation, ...). From the model Sculptor generates HTML documentation of all domain objects including their attributes and associations. Documentation of Services are also included. The generated result is located in src/generated/resources/DomainModelDoc.html<br /><br /><span style="font-weight:bold;">Improved Graphviz Visualization</span><br /><br />Several diagrams with different focus and level of detail are generated. They are also included in the generated documentation. <a href="http://fornax-sculptor.blogspot.com/2010/03/improved-graphviz-visualization.html">Samples here</a>. There is a new maven plugin fornax-graphviz-m2-plugin that generates images (.png) from the .dot files. <br /><br /><span style="font-weight:bold;">Syntax Diagrams</span><br /><br />We have mainly focused on sample based documentation. Some users have asked for more formal syntax description of the DSL. We have created <a href="http://fornax.itemis.de/confluence/x/OIBH">railroad syntax diagrams</a>.<br /><br /><span style="font-weight:bold;">Aggregate Syntax</span><br /><br />Aggregates can now be defined with the new belongsTo keyword. It is more informative than the previous !aggregateRoot.<br /><br /><pre class="brush:text"><br /> Entity Cargo {<br /> - TrackingId trackingId key<br /> - Location origin required<br /> - Location destination required<br /> - Itinerary itinerary nullable inverse opposite cargo<br /> }<br /><br /> ValueObject Itinerary {<br /> belongsTo Cargo<br /> not optimisticLocking<br /> not immutable<br /> - Cargo cargo nullable opposite itinerary<br /> - List<Leg> legs inverse<br /> }<br /><br /> "An itinerary consists of one or more legs."<br /> ValueObject Leg {<br /> belongsTo Cargo <br /> - CarrierMovement carrierMovement;<br /> - Location from;<br /> - Location ^to;<br /> }<br /></pre><br /><br /><span style="font-weight:bold;">Nullable in key</span><br /><br />It is now allowed to have some nullable fields as part a composite natural key.<br /><br /><pre class="brush:text"><br /> ValueObject HandlingEvent {<br /> - Type type key<br /> - CarrierMovement carrierMovement nullable key<br /> - Location location key<br /> DateTime completionTime key<br /> DateTime registrationTime<br /> - Cargo cargo key opposite events<br /> }<br /></pre><br /><br /><span style="font-weight:bold;">ToStringStyle</span><br /><br />We are using commons-lang for toString of domain objects. It has a <a href="http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/builder/ToStringStyle.html">style</a> parameter, which is now possible to define in sculptor-generator.properties. You can choose between several styles. I like this format:<br /><pre class="brush:text"><br />toStringStyle=SHORT_PREFIX_STYLE<br /></pre><br /><br />You can also override this for individual DomainObject with hint:<br /><pre class="brush:text"><br /> ValueObject Foo { <br /> hint="toStringStyle=MULTI_LINE_STYLE" <br /> String aaa <br /> String bbb <br /> } <br /></pre><br /><br /><span style="font-weight:bold;">databaseJoinTable</span><br /><br />It is possible to define many-to-many join table with databaseJoinTable and its columns with databaseColumn at both sides of the bidirectional association:<br /><pre class="brush:text"><br />- Set<@Media> existsInMedia opposite mediaCharacters<br /> databaseJoinTable="MED_CHR" databaseColumn="CHR"<br /></pre><br /><br />BTW opposite doesn't have to be defined last any more.<br /><br />Those keywords are also useful for unidirectional to-many associations. Additionally databaseJoinColumn is used, since there is no opposite side to define the column on.<br /><pre class="brush:text"><br />- Set<@Person> playedBy databaseJoinTable="CHR_PERS" <br /> databaseColumn="PERS" databaseJoinColumn="CHR"<br /></pre><br /><br /><span style="font-weight:bold;">Clob/Blob</span><br /><br />Clob and Blob are now supported with default java types String and byte[]. They are mapped with JPA @Lob.<br /><br /><span style="font-weight:bold;">GUI with Not Persistent Value Objects</span><br /><br />The structure of the persistent domain model might not always match the presentation, for example you might want a dialog for editing several domain objects in one single screen. Then you can create a non-persistent ValueObject with a corresponding Service. The application service handles the transformation between the presentation object and the persistent domain objects. More documentation and sample is available <a href="http://fornax.itemis.de/confluence/display/fornax/5.1+Web+CRUD+GUI+Tutorial+(CSC)#5.1WebCRUDGUITutorial%28CSC%29-NotPersistentValueObjects">here</a>.Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0tag:blogger.com,1999:blog-3314601722322098765.post-82679723069748332392010-07-11T20:00:00.000+02:002010-07-11T20:21:20.708+02:00Sculptor 1.9.0 - Support for MongoDB and Event-Driven ArchitectureThe Sculptor development team has a track record delivering around 3 releases per year. We have delivered 10 releases in total. That means that the core pieces are rock solid. I have personally used it successfully together with 15 other developers on daily basis for about a year now. It simply works very well.<br /><br />We care about bugfixing and making small improvements. At the same time we are excited about learning new technology and using emergent design. This release contains two new features in the area of scalability. Persistence backed with MongoDB and support for Event-Driven Architecture.<br /><br /><span style="font-weight:bold;">MongoDB</span> bridges the gap between key-value stores (which are fast and highly scalable) and traditional RDBMS systems (which provide rich queries and deep functionality). I think this makes MongoDB very interesting for applications that need high-performance and/or scalability, but also prefer using a rich persistent domain model with complex associations. The schema less structure is attractive from a developer productivity perspective, which is one of the two goals with Sculptor (quality is the other).<br /><br />Sculptor generates data mapper classes that converts domain objects to/from MongoDB data structures, DBObjects. This makes it easy to use a domain model à la DDD with automatic mapping to MongoDB data structures.<br /><br />Sculptor provides generic repository operations for use with MongoDB. This includes operations such as save, delete, findById, findByKey, findByCondition, and some more. You get CRUD operations, and GUI, for free.<br /><br />Queries can be expressed with a slick fluent api that support code completion and refactoring.<br /><br />Rich support for associations. Aggregates are stored as a embedded documents. Other associations are stored with referring ids. In the domain objects there are generated getters that lazily fetch associated objects from the ids. This means that you don't have to work with the ids yourself, you can follow associations as usual.<br /><br />Read more about how to use MongoDB with Sculptor <a href="http://fornax.itemis.de/confluence/x/CIBE">here</a>.<br /><br /><span style="font-weight:bold;">Event-Driven Architecture</span> (EDA) is a good complement to Domain-Driven Design. We think EDA is an important ingredient for building scalable systems. It is also an enabler for designing loosely coupled modules and bounded contexts.<br /><br />For this Sculptor makes it possible to define Domain Events in the model in similar way as Entities and Value Objects. Sculptor also provide a mechanism to publish and subscribe through a simple event bus. This is done either in a declarative way in the model, or programatically with a simple API.<br /><br />Implementations of the event bus that integrates with Apache Camel and Spring Integration are available out-of-the-box. <br /><br />In addition to publish/subscribe Sculptor also has support for CQRS and EventSourcing. <br /><br />CQRS is about separating commands (that change the data) from the queries (that read the data). Separate subsystems take care of answering queries (reporting) and the domain for processing and storing updates can stay focused. <br /><br />Event Sourcing makes it possible to see how we got to the current state and query how the state looked liked in the past. Essentially it means that we have to capture all changes to an application state as a sequence of events. Sculptor provides a default implementation of EventSourcing, which can be extended and customized to fit specific needs. <br /><br />Read more about how to use the new event features of Sculptor <a href="http://fornax.itemis.de/confluence/x/FgBL">here</a>. We will blog more about this topic later, so stay tuned.Patrikhttp://www.blogger.com/profile/11876565293495127382noreply@blogger.com0