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;
|
package com.baeldung.axon.commandmodel.order;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
import com.baeldung.axon.coreapi.commands.AddProductCommand;
|
||||||
import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand;
|
import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand;
|
||||||
import com.baeldung.axon.coreapi.commands.PlaceOrderCommand;
|
import com.baeldung.axon.coreapi.commands.PlaceOrderCommand;
|
||||||
import com.baeldung.axon.coreapi.commands.ShipOrderCommand;
|
import com.baeldung.axon.coreapi.commands.ShipOrderCommand;
|
||||||
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
|
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
|
||||||
import com.baeldung.axon.coreapi.events.OrderPlacedEvent;
|
import com.baeldung.axon.coreapi.events.OrderPlacedEvent;
|
||||||
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
|
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 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
|
@Aggregate
|
||||||
public class OrderAggregate {
|
public class OrderAggregate {
|
||||||
|
@ -22,13 +30,33 @@ public class OrderAggregate {
|
||||||
private String orderId;
|
private String orderId;
|
||||||
private boolean orderConfirmed;
|
private boolean orderConfirmed;
|
||||||
|
|
||||||
|
@AggregateMember
|
||||||
|
private Map<String, OrderLine> orderLines;
|
||||||
|
|
||||||
@CommandHandler
|
@CommandHandler
|
||||||
public OrderAggregate(PlaceOrderCommand command) {
|
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
|
@CommandHandler
|
||||||
public void handle(ConfirmOrderCommand command) {
|
public void handle(ConfirmOrderCommand command) {
|
||||||
|
if (orderConfirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
apply(new OrderConfirmedEvent(orderId));
|
apply(new OrderConfirmedEvent(orderId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +73,7 @@ public class OrderAggregate {
|
||||||
public void on(OrderPlacedEvent event) {
|
public void on(OrderPlacedEvent event) {
|
||||||
this.orderId = event.getOrderId();
|
this.orderId = event.getOrderId();
|
||||||
this.orderConfirmed = false;
|
this.orderConfirmed = false;
|
||||||
|
this.orderLines = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventSourcingHandler
|
@EventSourcingHandler
|
||||||
|
@ -52,8 +81,18 @@ public class OrderAggregate {
|
||||||
this.orderConfirmed = true;
|
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() {
|
protected OrderAggregate() {
|
||||||
// Required by Axon to build a default Aggregate prior to Event Sourcing
|
// 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