The development is moved to GitHub https://github.com/sculptor and the new blog is hosted there as well.
So take a look at Sculptors new home!
Sculptor 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.
Entity Person {
String firstName
String lastName
Date birthDate
PersonRepository {
findBy(String firstName);
}
}
PersonRepository {
findBornBefore(Date bd) condition="birthDate < :bd" orderBy="firstName";
findByName(String name) condition="lastName i= :name or firstName i= :name";
}
Book book = book()
.createdBy("me")
.createdDate(now)
.title("Ender's Game")
.isbn("Some-ISBN")
.addMediaCharacter(mediaCharacter()
.name("Ender")
.build())
.build();
Trait Ordered {
def boolean greaterThan(@Ordered other);
def boolean greaterThanOrEquals(@Ordered other);
def boolean lessThan(@Ordered other);
def boolean lessThanOrEquals(@Ordered other);
def abstract protected int compare(@Ordered other);
}
Entity Product with Ordered {
String name
}
Trait PriceTag {
- protected Money normalPrice
protected double discount
def Money price;
def Money price(String currency);
}
Entity Product with PriceTag {
String name
}
BasicType Money with Ordered {
BigDecimal amount
String currency
}
Trait PriceTag {
- protected Money normalPrice
protected double discount
def Money price;
def Money price(String currency);
def protected int compare(Ordered other);
}
Entity Product with Ordered with PriceTag {
String name
}
@Override
public InventoryItem findByKey(String itemId)
throws InventoryItemNotFoundException {
InventoryItem result = super.findByKey(itemId);
loadFromHistory(result);
return result;
}
private void loadFromHistory(InventoryItem entity) {
InventoryItemSnapshot snapshot = getInventoryItemSnapshotRepository()
.getLatestSnapshot(entity.getItemId());
entity.applySnapshot(snapshot);
long snapshotVersion = snapshot == null ? 0 : snapshot.getVersion();
List<InventoryItemEvent> history = getInventoryItemEventRepository()
.findAllAfter(entity.getItemId(), snapshotVersion);
entity.loadFromHistory(history);
}
ValueObject InventoryItemSnapshot {
String itemId index
boolean activated
Long version
Repository InventoryItemSnapshotRepository {
@InventoryItemSnapshot getLatestSnapshot(String itemId);
protected findByCondition(PagingParameter pagingParameter);
save;
}
}
Service InventoryItemSnapshotter {
subscribe to inventoryItemTopic
inject @InventoryItemRepository
inject @InventoryItemSnapshotRepository
}
public void receive(Event event) {
if (!(event instanceof InventoryItemEvent)) {
return;
}
InventoryItemEvent inventoryItemEvent = (InventoryItemEvent) event;
String itemId = inventoryItemEvent.getItemId();
InventoryItemSnapshot snapshot = getInventoryItemSnapshotRepository()
.getLatestSnapshot(itemId);
long snapshotVersion = snapshot == null ? 1 : snapshot.getVersion();
long eventVersion = inventoryItemEvent.getAggregateVersion() == null ? 1
: inventoryItemEvent.getAggregateVersion();
if (eventVersion - snapshotVersion >= VERSION_DELTA) {
takeSnapshot(itemId);
}
}
private void takeSnapshot(String itemId) {
InventoryItem item;
try {
item = getInventoryItemRepository().findByKey(itemId);
} catch (InventoryItemNotFoundException e) {
log.warn("takeSnapshot failed: " + e.getMessage());
return;
}
InventoryItemSnapshot snapshot = item.createSnapshot();
getInventoryItemSnapshotRepository().save(snapshot);
}
Service InventoryFacade {
inject @InventoryItemRepository
createInventoryItem(String itemId, String name);
deactivateInventoryItem(String itemId);
renameInventoryItem(String itemId, String newName);
checkInItemsToInventory(String itemId, int count);
removeItemsFromInventory(String itemId, int count);
}
public void deactivateInventoryItem(String itemId) {
InventoryItem item = tryGetItem(itemId);
item.deactivate();
getInventoryItemRepository().save(item);
}
public void deactivate() {
if (!isActivated())
throw new IllegalStateException("already deactivated");
applyChange(new InventoryItemDeactivated(new Date(), getItemId()));
}
private void applyChange(InventoryItemEvent event) {
applyChange(event, true);
}
private void applyChange(InventoryItemEvent event, boolean isNew) {
DynamicMethodDispatcher.dispatch(this, event, "apply");
if (isNew) {
changes.add(event);
} else {
setVersion(event.getAggregateVersion());
}
}
public void apply(InventoryItemDeactivated event) {
setActivated(false);
}
@Override
public InventoryItem save(InventoryItem entity) {
InventoryItem saved = super.save(entity);
List<InventoryItemEvent> changes = entity.getUncommittedChanges();
changes = applyVersionToChanges(changes, saved.getVersion());
for (InventoryItemEvent each : changes) {
getInventoryItemEventRepository().save(each);
}
entity.markChangesAsCommitted();
return saved;
}
private List<InventoryItemEvent> applyVersionToChanges(
List<InventoryItemEvent> changes, long version) {
List<InventoryItemEvent> result = new ArrayList<InventoryItemEvent>();
long sequence = version * 1000;
for (InventoryItemEvent each : changes) {
result.add(each.withAggregateVersion(version).withChangeSequence(
sequence));
sequence++;
}
return result;
}
abstract DomainEvent InventoryItemEvent {
persistent
String itemId index
Long aggregateVersion nullable
Long changeSequence nullable
Repository InventoryItemEventRepository {
save publish to inventoryItemTopic;
List<@InventoryItemEvent> findAllForItem(String itemId);
protected findByCondition;
}
}
DomainEvent InventoryItemDeactivated extends @InventoryItemEvent {
}
Service InventoryListView {
subscribe to inventoryItemTopic
inject @InventoryItemListRepository
}
Service InventoryItemDetailView {
subscribe to inventoryItemTopic
inject @InventoryItemDetailsRepository
}
@Override
public InventoryItem findByKey(String itemId)
throws InventoryItemNotFoundException {
InventoryItem result = super.findByKey(itemId);
loadFromHistory(result);
return result;
}
private void loadFromHistory(InventoryItem entity) {
List<InventoryItemEvent> history = getInventoryItemEventRepository()
.findAllForItem(entity.getItemId());
entity.loadFromHistory(history);
}
public List<InventoryItemEvent> findAllForItem(String itemId) {
List<ConditionalCriteria> criteria = criteriaFor(
InventoryItemEvent.class).withProperty(itemId()).eq(itemId)
.orderBy(changeSequence()).build();
return findByCondition(criteria);
}
public void loadFromHistory(List<InventoryItemEvent> history) {
for (InventoryItemEvent each : history) {
applyChange(each, false);
}
}
private void applyChange(InventoryItemEvent event, boolean isNew) {
DynamicMethodDispatcher.dispatch(this, event, "apply");
if (isNew) {
changes.add(event);
} else {
setVersion(event.getAggregateVersion());
}
}
public void apply(InventoryItemCreated event) {
setActivated(true);
}
public void apply(InventoryItemDeactivated event) {
setActivated(false);
}
public void apply(Object other) {
// ignore
}