Rename API in line with adjusted approach

Change PlaceOrderCommand/OrderPlacedEvent to
CreateOrderCommand/OrderCreatedEvent. Placed suggests it is already
placed, meaning products cannot be changed. However with the new
OrderLine member and its operations it's no longer correct to state the
order placed upon creation. Furthermore, the OrderedProduct is no longer
 a single product, but contains several. Renaming this to Order is more
 in line with what this query model resembles

#BAEL-4767
This commit is contained in:
Steven van Beelen 2021-03-19 11:35:31 +01:00
parent 70189df008
commit 2b351eda7a
10 changed files with 149 additions and 151 deletions

View File

@ -2,10 +2,10 @@ 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.CreateOrderCommand;
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.OrderCreatedEvent;
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
import com.baeldung.axon.coreapi.events.ProductRemovedEvent;
@ -34,8 +34,8 @@ public class OrderAggregate {
private Map<String, OrderLine> orderLines;
@CommandHandler
public OrderAggregate(PlaceOrderCommand command) {
apply(new OrderPlacedEvent(command.getOrderId()));
public OrderAggregate(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
@CommandHandler
@ -70,7 +70,7 @@ public class OrderAggregate {
}
@EventSourcingHandler
public void on(OrderPlacedEvent event) {
public void on(OrderCreatedEvent event) {
this.orderId = event.getOrderId();
this.orderConfirmed = false;
this.orderLines = new HashMap<>();

View File

@ -4,12 +4,12 @@ import org.axonframework.modelling.command.TargetAggregateIdentifier;
import java.util.Objects;
public class PlaceOrderCommand {
public class CreateOrderCommand {
@TargetAggregateIdentifier
private final String orderId;
public PlaceOrderCommand(String orderId) {
public CreateOrderCommand(String orderId) {
this.orderId = orderId;
}
@ -25,7 +25,7 @@ public class PlaceOrderCommand {
if (o == null || getClass() != o.getClass()) {
return false;
}
PlaceOrderCommand that = (PlaceOrderCommand) o;
CreateOrderCommand that = (CreateOrderCommand) o;
return Objects.equals(orderId, that.orderId);
}
@ -36,7 +36,7 @@ public class PlaceOrderCommand {
@Override
public String toString() {
return "PlaceOrderCommand{" +
return "CreateOrderCommand{" +
"orderId='" + orderId + '\'' +
'}';
}

View File

@ -2,11 +2,11 @@ package com.baeldung.axon.coreapi.events;
import java.util.Objects;
public class OrderPlacedEvent {
public class OrderCreatedEvent {
private final String orderId;
public OrderPlacedEvent(String orderId) {
public OrderCreatedEvent(String orderId) {
this.orderId = orderId;
}
@ -22,7 +22,7 @@ public class OrderPlacedEvent {
if (o == null || getClass() != o.getClass()) {
return false;
}
OrderPlacedEvent that = (OrderPlacedEvent) o;
OrderCreatedEvent that = (OrderCreatedEvent) o;
return Objects.equals(orderId, that.orderId);
}
@ -33,7 +33,7 @@ public class OrderPlacedEvent {
@Override
public String toString() {
return "OrderPlacedEvent{" +
return "OrderCreatedEvent{" +
"orderId='" + orderId + '\'' +
'}';
}

View File

@ -4,16 +4,16 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class OrderedProduct {
public class Order {
private final String orderId;
private final Map<String, Integer> products;
private OrderStatus orderStatus;
public OrderedProduct(String orderId) {
public Order(String orderId) {
this.orderId = orderId;
this.products = new HashMap<>();
orderStatus = OrderStatus.PLACED;
orderStatus = OrderStatus.CREATED;
}
public String getOrderId() {
@ -61,8 +61,9 @@ public class OrderedProduct {
if (o == null || getClass() != o.getClass()) {
return false;
}
OrderedProduct that = (OrderedProduct) o;
return Objects.equals(orderId, that.orderId) && Objects.equals(products, that.products)
Order that = (Order) o;
return Objects.equals(orderId, that.orderId)
&& Objects.equals(products, that.products)
&& orderStatus == that.orderStatus;
}
@ -73,7 +74,7 @@ public class OrderedProduct {
@Override
public String toString() {
return "OrderedProduct{" +
return "Order{" +
"orderId='" + orderId + '\'' +
", products=" + products +
", orderStatus=" + orderStatus +

View File

@ -2,6 +2,5 @@ package com.baeldung.axon.coreapi.queries;
public enum OrderStatus {
PLACED, CONFIRMED, SHIPPED
CREATED, CONFIRMED, SHIPPED
}

View File

@ -2,12 +2,12 @@ package com.baeldung.axon.gui;
import com.baeldung.axon.coreapi.commands.AddProductCommand;
import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand;
import com.baeldung.axon.coreapi.commands.CreateOrderCommand;
import com.baeldung.axon.coreapi.commands.DecrementProductCountCommand;
import com.baeldung.axon.coreapi.commands.IncrementProductCountCommand;
import com.baeldung.axon.coreapi.commands.PlaceOrderCommand;
import com.baeldung.axon.coreapi.commands.ShipOrderCommand;
import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery;
import com.baeldung.axon.coreapi.queries.OrderedProduct;
import com.baeldung.axon.coreapi.queries.Order;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.messaging.responsetypes.ResponseTypes;
import org.axonframework.queryhandling.QueryGateway;
@ -34,7 +34,7 @@ public class OrderRestEndpoint {
@PostMapping("/ship-order")
public void shipOrder() {
String orderId = UUID.randomUUID().toString();
commandGateway.send(new PlaceOrderCommand(orderId));
commandGateway.send(new CreateOrderCommand(orderId));
commandGateway.send(new AddProductCommand(orderId, "Deluxe Chair"));
commandGateway.send(new ConfirmOrderCommand(orderId));
commandGateway.send(new ShipOrderCommand(orderId));
@ -43,20 +43,20 @@ public class OrderRestEndpoint {
@PostMapping("/ship-unconfirmed-order")
public void shipUnconfirmedOrder() {
String orderId = UUID.randomUUID().toString();
commandGateway.send(new PlaceOrderCommand(orderId));
commandGateway.send(new CreateOrderCommand(orderId));
commandGateway.send(new AddProductCommand(orderId, "Deluxe Chair"));
// This throws an exception, as an Order cannot be shipped if it has not been confirmed yet.
commandGateway.send(new ShipOrderCommand(orderId));
}
@PostMapping("/order")
public CompletableFuture<String> placeOrder() {
return placeOrder(UUID.randomUUID().toString());
public CompletableFuture<String> createOrder() {
return createOrder(UUID.randomUUID().toString());
}
@PostMapping("/order/{order-id}")
public CompletableFuture<String> placeOrder(@PathVariable("order-id") String orderId) {
return commandGateway.send(new PlaceOrderCommand(orderId));
public CompletableFuture<String> createOrder(@PathVariable("order-id") String orderId) {
return commandGateway.send(new CreateOrderCommand(orderId));
}
@PostMapping("/order/{order-id}/product/{product-id}")
@ -88,9 +88,7 @@ public class OrderRestEndpoint {
}
@GetMapping("/all-orders")
public CompletableFuture<List<OrderedProduct>> findAllOrderedProducts() {
return queryGateway.query(
new FindAllOrderedProductsQuery(), ResponseTypes.multipleInstancesOf(OrderedProduct.class)
);
public CompletableFuture<List<Order>> findAllOrders() {
return queryGateway.query(new FindAllOrderedProductsQuery(), ResponseTypes.multipleInstancesOf(Order.class));
}
}

View File

@ -1,86 +0,0 @@
package com.baeldung.axon.querymodel;
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.ProductCountDecrementedEvent;
import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent;
import com.baeldung.axon.coreapi.events.ProductRemovedEvent;
import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery;
import com.baeldung.axon.coreapi.queries.OrderedProduct;
import org.axonframework.config.ProcessingGroup;
import org.axonframework.eventhandling.EventHandler;
import org.axonframework.queryhandling.QueryHandler;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@ProcessingGroup("ordered-products")
public class OrderedProductsEventHandler {
private final Map<String, OrderedProduct> orderedProducts = new HashMap<>();
@EventHandler
public void on(OrderPlacedEvent event) {
String orderId = event.getOrderId();
orderedProducts.put(orderId, new OrderedProduct(orderId));
}
@EventHandler
public void on(ProductAddedEvent event) {
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.addProduct(event.getProductId());
return orderedProduct;
});
}
@EventHandler
public void on(ProductCountIncrementedEvent event) {
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.incrementProductInstance(event.getProductId());
return orderedProduct;
});
}
@EventHandler
public void on(ProductCountDecrementedEvent event) {
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.decrementProductInstance(event.getProductId());
return orderedProduct;
});
}
@EventHandler
public void on(ProductRemovedEvent event) {
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.removeProduct(event.getProductId());
return orderedProduct;
});
}
@EventHandler
public void on(OrderConfirmedEvent event) {
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.setOrderConfirmed();
return orderedProduct;
});
}
@EventHandler
public void on(OrderShippedEvent event) {
orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> {
orderedProduct.setOrderShipped();
return orderedProduct;
});
}
@QueryHandler
public List<OrderedProduct> handle(FindAllOrderedProductsQuery query) {
return new ArrayList<>(orderedProducts.values());
}
}

View File

@ -0,0 +1,86 @@
package com.baeldung.axon.querymodel;
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
import com.baeldung.axon.coreapi.events.OrderCreatedEvent;
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
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.queries.FindAllOrderedProductsQuery;
import com.baeldung.axon.coreapi.queries.Order;
import org.axonframework.config.ProcessingGroup;
import org.axonframework.eventhandling.EventHandler;
import org.axonframework.queryhandling.QueryHandler;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@ProcessingGroup("orders")
public class OrdersEventHandler {
private final Map<String, Order> orders = new HashMap<>();
@EventHandler
public void on(OrderCreatedEvent event) {
String orderId = event.getOrderId();
orders.put(orderId, new Order(orderId));
}
@EventHandler
public void on(ProductAddedEvent event) {
orders.computeIfPresent(event.getOrderId(), (orderId, order) -> {
order.addProduct(event.getProductId());
return order;
});
}
@EventHandler
public void on(ProductCountIncrementedEvent event) {
orders.computeIfPresent(event.getOrderId(), (orderId, order) -> {
order.incrementProductInstance(event.getProductId());
return order;
});
}
@EventHandler
public void on(ProductCountDecrementedEvent event) {
orders.computeIfPresent(event.getOrderId(), (orderId, order) -> {
order.decrementProductInstance(event.getProductId());
return order;
});
}
@EventHandler
public void on(ProductRemovedEvent event) {
orders.computeIfPresent(event.getOrderId(), (orderId, order) -> {
order.removeProduct(event.getProductId());
return order;
});
}
@EventHandler
public void on(OrderConfirmedEvent event) {
orders.computeIfPresent(event.getOrderId(), (orderId, order) -> {
order.setOrderConfirmed();
return order;
});
}
@EventHandler
public void on(OrderShippedEvent event) {
orders.computeIfPresent(event.getOrderId(), (orderId, order) -> {
order.setOrderShipped();
return order;
});
}
@QueryHandler
public List<Order> handle(FindAllOrderedProductsQuery query) {
return new ArrayList<>(orders.values());
}
}

View File

@ -1,8 +1,8 @@
### Place Order, Add Product, Confirm and Ship Order
### Create Order, Add Product, Confirm and Ship Order
POST http://localhost:8080/ship-order
### Place Order, Add Product and Ship Order
### Create Order, Add Product and Ship Order
POST http://localhost:8080/ship-unconfirmed-order
@ -10,7 +10,7 @@ POST http://localhost:8080/ship-unconfirmed-order
GET http://localhost:8080/all-orders
### Place Order with id 666a1661-474d-4046-8b12-8b5896312768
### Create Order with id 666a1661-474d-4046-8b12-8b5896312768
POST http://localhost:8080/order/666a1661-474d-4046-8b12-8b5896312768

View File

@ -3,12 +3,12 @@ package com.baeldung.axon.commandmodel;
import com.baeldung.axon.commandmodel.order.OrderAggregate;
import com.baeldung.axon.coreapi.commands.AddProductCommand;
import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand;
import com.baeldung.axon.coreapi.commands.CreateOrderCommand;
import com.baeldung.axon.coreapi.commands.DecrementProductCountCommand;
import com.baeldung.axon.coreapi.commands.IncrementProductCountCommand;
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.OrderCreatedEvent;
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent;
@ -37,37 +37,37 @@ class OrderAggregateUnitTest {
}
@Test
void giveNoPriorActivity_whenPlaceOrderCommand_thenShouldPublishOrderPlacedEvent() {
void giveNoPriorActivity_whenCreateOrderCommand_thenShouldPublishOrderCreatedEvent() {
fixture.givenNoPriorActivity()
.when(new PlaceOrderCommand(ORDER_ID))
.expectEvents(new OrderPlacedEvent(ORDER_ID));
.when(new CreateOrderCommand(ORDER_ID))
.expectEvents(new OrderCreatedEvent(ORDER_ID));
}
@Test
void givenOrderPlacedEvent_whenAddProductCommand_thenShouldPublishProductAddedEvent() {
fixture.given(new OrderPlacedEvent(ORDER_ID))
void givenOrderCreatedEvent_whenAddProductCommand_thenShouldPublishProductAddedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID))
.when(new AddProductCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductAddedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderPlacedEventAndProductAddedEvent_whenAddProductCommandForSameProductId_thenShouldThrowDuplicateOrderLineException() {
fixture.given(new OrderPlacedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
void givenOrderCreatedEventAndProductAddedEvent_whenAddProductCommandForSameProductId_thenShouldThrowDuplicateOrderLineException() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
.when(new AddProductCommand(ORDER_ID, PRODUCT_ID))
.expectException(DuplicateOrderLineException.class)
.expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(PRODUCT_ID)));
}
@Test
void givenOrderPlacedEventAndProductAddedEvent_whenIncrementProductCountCommand_thenShouldPublishProductCountIncrementedEvent() {
fixture.given(new OrderPlacedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
void givenOrderCreatedEventAndProductAddedEvent_whenIncrementProductCountCommand_thenShouldPublishProductCountIncrementedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
.when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderPlacedEventProductAddedEventAndProductCountIncrementedEvent_whenDecrementProductCountCommand_thenShouldPublishProductCountDecrementedEvent() {
fixture.given(new OrderPlacedEvent(ORDER_ID),
void givenOrderCreatedEventProductAddedEventAndProductCountIncrementedEvent_whenDecrementProductCountCommand_thenShouldPublishProductCountDecrementedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID),
new ProductAddedEvent(ORDER_ID, PRODUCT_ID),
new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID))
.when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID))
@ -75,51 +75,51 @@ class OrderAggregateUnitTest {
}
@Test
void givenOrderPlacedEventAndProductAddedEvent_whenDecrementProductCountCommand_thenShouldPublishProductRemovedEvent() {
fixture.given(new OrderPlacedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
void givenOrderCreatedEventAndProductAddedEvent_whenDecrementProductCountCommand_thenShouldPublishProductRemovedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
.when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductRemovedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderPlacedEvent_whenConfirmOrderCommand_thenShouldPublishOrderConfirmedEvent() {
fixture.given(new OrderPlacedEvent(ORDER_ID))
void givenOrderCreatedEvent_whenConfirmOrderCommand_thenShouldPublishOrderConfirmedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID))
.when(new ConfirmOrderCommand(ORDER_ID))
.expectEvents(new OrderConfirmedEvent(ORDER_ID));
}
@Test
void givenOrderPlacedEventAndOrderConfirmedEvent_whenConfirmOrderCommand_thenExpectNoEvents() {
fixture.given(new OrderPlacedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
void givenOrderCreatedEventAndOrderConfirmedEvent_whenConfirmOrderCommand_thenExpectNoEvents() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new ConfirmOrderCommand(ORDER_ID))
.expectNoEvents();
}
@Test
void givenOrderPlacedEvent_whenShipOrderCommand_thenShouldThrowUnconfirmedOrderException() {
fixture.given(new OrderPlacedEvent(ORDER_ID))
void givenOrderCreatedEvent_whenShipOrderCommand_thenShouldThrowUnconfirmedOrderException() {
fixture.given(new OrderCreatedEvent(ORDER_ID))
.when(new ShipOrderCommand(ORDER_ID))
.expectException(UnconfirmedOrderException.class);
}
@Test
void givenOrderPlacedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() {
fixture.given(new OrderPlacedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
void givenOrderCreatedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new ShipOrderCommand(ORDER_ID))
.expectEvents(new OrderShippedEvent(ORDER_ID));
}
@Test
void givenOrderPlacedEventProductAndOrderConfirmedEvent_whenAddProductCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderPlacedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
void givenOrderCreatedEventProductAndOrderConfirmedEvent_whenAddProductCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new AddProductCommand(ORDER_ID, PRODUCT_ID))
.expectException(OrderAlreadyConfirmedException.class)
.expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID)));
}
@Test
void givenOrderPlacedEventProductAddedEventAndOrderConfirmedEvent_whenIncrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderPlacedEvent(ORDER_ID),
void givenOrderCreatedEventProductAddedEventAndOrderConfirmedEvent_whenIncrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderCreatedEvent(ORDER_ID),
new ProductAddedEvent(ORDER_ID, PRODUCT_ID),
new OrderConfirmedEvent(ORDER_ID))
.when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID))
@ -128,8 +128,8 @@ class OrderAggregateUnitTest {
}
@Test
void givenOrderPlacedEventProductAddedEventAndOrderConfirmedEvent_whenDecrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderPlacedEvent(ORDER_ID),
void givenOrderCreatedEventProductAddedEventAndOrderConfirmedEvent_whenDecrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderCreatedEvent(ORDER_ID),
new ProductAddedEvent(ORDER_ID, PRODUCT_ID),
new OrderConfirmedEvent(ORDER_ID))
.when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID))