Update Command Model
Adjust the OrderAggregate to contain an OrderLine aggregate member. The OrderLine is added as soon as a Product is added through the AddProductCommand. The OrderLine member is capable of handling the increment and decrement product count commands, to increase/decrease the number of instances for that OrderLine. Decreasing the count below 1 will publish the ProductRemovedEvent from within the OrderLine. Additional business validation is added to unsure a given Product isn't added twice (adding a second should go through increment) and that the products aren't adjusted as soon as the product is confirmed. #BAEL-4767
This commit is contained in:
parent
ef1167b037
commit
886368a4c3
|
@ -1,19 +1,27 @@
|
|||
package com.baeldung.axon.commandmodel;
|
||||
|
||||
import static org.axonframework.modelling.command.AggregateLifecycle.apply;
|
||||
|
||||
import org.axonframework.commandhandling.CommandHandler;
|
||||
import org.axonframework.eventsourcing.EventSourcingHandler;
|
||||
import org.axonframework.modelling.command.AggregateIdentifier;
|
||||
import org.axonframework.spring.stereotype.Aggregate;
|
||||
package com.baeldung.axon.commandmodel.order;
|
||||
|
||||
import com.baeldung.axon.coreapi.commands.AddProductCommand;
|
||||
import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand;
|
||||
import com.baeldung.axon.coreapi.commands.PlaceOrderCommand;
|
||||
import com.baeldung.axon.coreapi.commands.ShipOrderCommand;
|
||||
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
|
||||
import com.baeldung.axon.coreapi.events.OrderPlacedEvent;
|
||||
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
|
||||
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
|
||||
import com.baeldung.axon.coreapi.events.ProductRemovedEvent;
|
||||
import com.baeldung.axon.coreapi.exceptions.DuplicateOrderLineException;
|
||||
import com.baeldung.axon.coreapi.exceptions.OrderAlreadyConfirmedException;
|
||||
import com.baeldung.axon.coreapi.exceptions.UnconfirmedOrderException;
|
||||
import org.axonframework.commandhandling.CommandHandler;
|
||||
import org.axonframework.eventsourcing.EventSourcingHandler;
|
||||
import org.axonframework.modelling.command.AggregateIdentifier;
|
||||
import org.axonframework.modelling.command.AggregateMember;
|
||||
import org.axonframework.spring.stereotype.Aggregate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.axonframework.modelling.command.AggregateLifecycle.apply;
|
||||
|
||||
@Aggregate
|
||||
public class OrderAggregate {
|
||||
|
@ -22,13 +30,33 @@ public class OrderAggregate {
|
|||
private String orderId;
|
||||
private boolean orderConfirmed;
|
||||
|
||||
@AggregateMember
|
||||
private Map<String, OrderLine> orderLines;
|
||||
|
||||
@CommandHandler
|
||||
public OrderAggregate(PlaceOrderCommand command) {
|
||||
apply(new OrderPlacedEvent(command.getOrderId(), command.getProduct()));
|
||||
apply(new OrderPlacedEvent(command.getOrderId()));
|
||||
}
|
||||
|
||||
@CommandHandler
|
||||
public void handle(AddProductCommand command) {
|
||||
if (orderConfirmed) {
|
||||
throw new OrderAlreadyConfirmedException(orderId);
|
||||
}
|
||||
|
||||
String productId = command.getProductId();
|
||||
if (orderLines.containsKey(productId)) {
|
||||
throw new DuplicateOrderLineException(productId);
|
||||
}
|
||||
apply(new ProductAddedEvent(orderId, productId));
|
||||
}
|
||||
|
||||
@CommandHandler
|
||||
public void handle(ConfirmOrderCommand command) {
|
||||
if (orderConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
apply(new OrderConfirmedEvent(orderId));
|
||||
}
|
||||
|
||||
|
@ -45,6 +73,7 @@ public class OrderAggregate {
|
|||
public void on(OrderPlacedEvent event) {
|
||||
this.orderId = event.getOrderId();
|
||||
this.orderConfirmed = false;
|
||||
this.orderLines = new HashMap<>();
|
||||
}
|
||||
|
||||
@EventSourcingHandler
|
||||
|
@ -52,8 +81,18 @@ public class OrderAggregate {
|
|||
this.orderConfirmed = true;
|
||||
}
|
||||
|
||||
@EventSourcingHandler
|
||||
public void on(ProductAddedEvent event) {
|
||||
String productId = event.getProductId();
|
||||
this.orderLines.put(productId, new OrderLine(productId));
|
||||
}
|
||||
|
||||
@EventSourcingHandler
|
||||
public void on(ProductRemovedEvent event) {
|
||||
this.orderLines.remove(event.getProductId());
|
||||
}
|
||||
|
||||
protected OrderAggregate() {
|
||||
// Required by Axon to build a default Aggregate prior to Event Sourcing
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.baeldung.axon.commandmodel.order;
|
||||
|
||||
import com.baeldung.axon.coreapi.commands.DecrementProductCountCommand;
|
||||
import com.baeldung.axon.coreapi.commands.IncrementProductCountCommand;
|
||||
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
|
||||
import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent;
|
||||
import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent;
|
||||
import com.baeldung.axon.coreapi.events.ProductRemovedEvent;
|
||||
import com.baeldung.axon.coreapi.exceptions.OrderAlreadyConfirmedException;
|
||||
import org.axonframework.commandhandling.CommandHandler;
|
||||
import org.axonframework.eventsourcing.EventSourcingHandler;
|
||||
import org.axonframework.modelling.command.EntityId;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.axonframework.modelling.command.AggregateLifecycle.apply;
|
||||
|
||||
public class OrderLine {
|
||||
|
||||
@EntityId
|
||||
private final String productId;
|
||||
private Integer count;
|
||||
private boolean orderConfirmed;
|
||||
|
||||
public OrderLine(String productId) {
|
||||
this.productId = productId;
|
||||
this.count = 1;
|
||||
}
|
||||
|
||||
@CommandHandler
|
||||
public void handle(IncrementProductCountCommand command) {
|
||||
if (orderConfirmed) {
|
||||
throw new OrderAlreadyConfirmedException(command.getOrderId());
|
||||
}
|
||||
|
||||
apply(new ProductCountIncrementedEvent(command.getOrderId(), productId));
|
||||
}
|
||||
|
||||
@CommandHandler
|
||||
public void handle(DecrementProductCountCommand command) {
|
||||
if (orderConfirmed) {
|
||||
throw new OrderAlreadyConfirmedException(command.getOrderId());
|
||||
}
|
||||
|
||||
if (count <= 1) {
|
||||
apply(new ProductRemovedEvent(command.getOrderId(), productId));
|
||||
} else {
|
||||
apply(new ProductCountDecrementedEvent(command.getOrderId(), productId));
|
||||
}
|
||||
}
|
||||
|
||||
@EventSourcingHandler
|
||||
public void on(ProductCountIncrementedEvent event) {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
@EventSourcingHandler
|
||||
public void on(ProductCountDecrementedEvent event) {
|
||||
this.count--;
|
||||
}
|
||||
|
||||
@EventSourcingHandler
|
||||
public void on(OrderConfirmedEvent event) {
|
||||
this.orderConfirmed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OrderLine orderLine = (OrderLine) o;
|
||||
return Objects.equals(productId, orderLine.productId) && Objects.equals(count, orderLine.count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(productId, count);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue