diff --git a/axon/pom.xml b/axon/pom.xml index c643ea9e57..598dc820e5 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -4,29 +4,61 @@ 4.0.0 axon axon - + Basic Axon Framework with Spring Boot configuration tutorial + - parent-modules com.baeldung - 1.0.0-SNAPSHOT + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + org.axonframework + axon-spring-boot-starter + ${axon.version} + + + org.axonframework + axon-server-connector + + + + org.axonframework axon-test ${axon.version} test + - org.axonframework - axon-core - ${axon.version} + org.springframework.boot + spring-boot-autoconfigure + 2.1.1.RELEASE + compile + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime - 3.0.2 + 4.0.3 \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java deleted file mode 100644 index 77b50d09bd..0000000000 --- a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.axon; - -import com.baeldung.axon.aggregates.MessagesAggregate; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; -import com.baeldung.axon.eventhandlers.MessagesEventHandler; -import org.axonframework.commandhandling.AggregateAnnotationCommandHandler; -import org.axonframework.commandhandling.CommandBus; -import org.axonframework.commandhandling.SimpleCommandBus; -import org.axonframework.commandhandling.gateway.CommandGateway; -import org.axonframework.commandhandling.gateway.DefaultCommandGateway; -import org.axonframework.eventhandling.AnnotationEventListenerAdapter; -import org.axonframework.eventsourcing.EventSourcingRepository; -import org.axonframework.eventsourcing.eventstore.EmbeddedEventStore; -import org.axonframework.eventsourcing.eventstore.EventStore; -import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine; - -import java.util.UUID; - -public class MessagesRunner { - - public static void main(String[] args) { - CommandBus commandBus = new SimpleCommandBus(); - - CommandGateway commandGateway = new DefaultCommandGateway(commandBus); - - EventStore eventStore = new EmbeddedEventStore(new InMemoryEventStorageEngine()); - - EventSourcingRepository repository = - new EventSourcingRepository<>(MessagesAggregate.class, eventStore); - - - AggregateAnnotationCommandHandler messagesAggregateAggregateAnnotationCommandHandler = - new AggregateAnnotationCommandHandler(MessagesAggregate.class, repository); - messagesAggregateAggregateAnnotationCommandHandler.subscribe(commandBus); - - final AnnotationEventListenerAdapter annotationEventListenerAdapter = - new AnnotationEventListenerAdapter(new MessagesEventHandler()); - eventStore.subscribe(eventMessages -> eventMessages.forEach(e -> { - try { - annotationEventListenerAdapter.handle(e); - } catch (Exception e1) { - throw new RuntimeException(e1); - - } - } - - )); - - final String itemId = UUID.randomUUID().toString(); - commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); - commandGateway.send(new MarkReadMessageCommand(itemId)); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/OrderApplication.java b/axon/src/main/java/com/baeldung/axon/OrderApplication.java new file mode 100644 index 0000000000..8f507e141c --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/OrderApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.axon; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class OrderApplication { + + public static void main(String[] args) { + SpringApplication.run(OrderApplication.class, args); + } + +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java deleted file mode 100644 index e762604b74..0000000000 --- a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.axon.aggregates; - -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; -import org.axonframework.commandhandling.CommandHandler; -import org.axonframework.commandhandling.model.AggregateIdentifier; -import org.axonframework.eventhandling.EventHandler; - -import static org.axonframework.commandhandling.model.AggregateLifecycle.apply; - - -public class MessagesAggregate { - - @AggregateIdentifier - private String id; - - public MessagesAggregate() { - } - - @CommandHandler - public MessagesAggregate(CreateMessageCommand command) { - apply(new MessageCreatedEvent(command.getId(), command.getText())); - } - - @EventHandler - public void on(MessageCreatedEvent event) { - this.id = event.getId(); - } - - @CommandHandler - public void markRead(MarkReadMessageCommand command) { - apply(new MessageReadEvent(id)); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java new file mode 100644 index 0000000000..b37b2fdd66 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java @@ -0,0 +1,58 @@ +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; + +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; + +@Aggregate +public class OrderAggregate { + + @AggregateIdentifier + private String orderId; + private boolean orderConfirmed; + + @CommandHandler + public OrderAggregate(PlaceOrderCommand command) { + apply(new OrderPlacedEvent(command.getOrderId(), command.getProduct())); + } + + @CommandHandler + public void handle(ConfirmOrderCommand command) { + apply(new OrderConfirmedEvent(orderId)); + } + + @CommandHandler + public void handle(ShipOrderCommand command) { + if (!orderConfirmed) { + throw new IllegalStateException("Cannot ship an order which has not been confirmed yet."); + } + + apply(new OrderShippedEvent(orderId)); + } + + @EventSourcingHandler + public void on(OrderPlacedEvent event) { + this.orderId = event.getOrderId(); + orderConfirmed = false; + } + + @EventSourcingHandler + public void on(OrderConfirmedEvent event) { + orderConfirmed = true; + } + + protected OrderAggregate() { + // Required by Axon to build a default Aggregate prior to Event Sourcing + } + +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java deleted file mode 100644 index d0651bf12e..0000000000 --- a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.axon.commands; - - -import org.axonframework.commandhandling.TargetAggregateIdentifier; - -public class CreateMessageCommand { - - @TargetAggregateIdentifier - private final String id; - private final String text; - - public CreateMessageCommand(String id, String text) { - this.id = id; - this.text = text; - } - - public String getId() { - return id; - } - - public String getText() { - return text; - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java deleted file mode 100644 index e66582d9ec..0000000000 --- a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.baeldung.axon.commands; - - -import org.axonframework.commandhandling.TargetAggregateIdentifier; - -public class MarkReadMessageCommand { - - @TargetAggregateIdentifier - private final String id; - - public MarkReadMessageCommand(String id) { - this.id = id; - } - - public String getId() { - return id; - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java new file mode 100644 index 0000000000..244b69f3b7 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java @@ -0,0 +1,43 @@ +package com.baeldung.axon.coreapi.commands; + +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +import java.util.Objects; + +public class ConfirmOrderCommand { + + @TargetAggregateIdentifier + private final String orderId; + + public ConfirmOrderCommand(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ConfirmOrderCommand other = (ConfirmOrderCommand) obj; + return Objects.equals(this.orderId, other.orderId); + } + + @Override + public String toString() { + return "ConfirmOrderCommand{" + + "orderId='" + orderId + '\'' + + '}'; + } +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java new file mode 100644 index 0000000000..c70d503050 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java @@ -0,0 +1,51 @@ +package com.baeldung.axon.coreapi.commands; + +import java.util.Objects; + +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +public class PlaceOrderCommand { + + @TargetAggregateIdentifier + private final String orderId; + private final String product; + + public PlaceOrderCommand(String orderId, String product) { + this.orderId = orderId; + this.product = product; + } + + public String getOrderId() { + return orderId; + } + + public String getProduct() { + return product; + } + + @Override + public int hashCode() { + return Objects.hash(orderId, product); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final PlaceOrderCommand other = (PlaceOrderCommand) obj; + return Objects.equals(this.orderId, other.orderId) + && Objects.equals(this.product, other.product); + } + + @Override + public String toString() { + return "PlaceOrderCommand{" + + "orderId='" + orderId + '\'' + + ", product='" + product + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java new file mode 100644 index 0000000000..7312bc1fdb --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java @@ -0,0 +1,43 @@ +package com.baeldung.axon.coreapi.commands; + +import java.util.Objects; + +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +public class ShipOrderCommand { + + @TargetAggregateIdentifier + private final String orderId; + + public ShipOrderCommand(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ShipOrderCommand other = (ShipOrderCommand) obj; + return Objects.equals(this.orderId, other.orderId); + } + + @Override + public String toString() { + return "ShipOrderCommand{" + + "orderId='" + orderId + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java new file mode 100644 index 0000000000..d2b7d58435 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java @@ -0,0 +1,40 @@ +package com.baeldung.axon.coreapi.events; + +import java.util.Objects; + +public class OrderConfirmedEvent { + + private final String orderId; + + public OrderConfirmedEvent(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderConfirmedEvent other = (OrderConfirmedEvent) obj; + return Objects.equals(this.orderId, other.orderId); + } + + @Override + public String toString() { + return "OrderConfirmedEvent{" + + "orderId='" + orderId + '\'' + + '}'; + } +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java new file mode 100644 index 0000000000..06de4c5f9f --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java @@ -0,0 +1,48 @@ +package com.baeldung.axon.coreapi.events; + +import java.util.Objects; + +public class OrderPlacedEvent { + + private final String orderId; + private final String product; + + public OrderPlacedEvent(String orderId, String product) { + this.orderId = orderId; + this.product = product; + } + + public String getOrderId() { + return orderId; + } + + public String getProduct() { + return product; + } + + @Override + public int hashCode() { + return Objects.hash(orderId, product); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderPlacedEvent other = (OrderPlacedEvent) obj; + return Objects.equals(this.orderId, other.orderId) + && Objects.equals(this.product, other.product); + } + + @Override + public String toString() { + return "OrderPlacedEvent{" + + "orderId='" + orderId + '\'' + + ", product='" + product + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java new file mode 100644 index 0000000000..76aa684629 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java @@ -0,0 +1,40 @@ +package com.baeldung.axon.coreapi.events; + +import java.util.Objects; + +public class OrderShippedEvent { + + private final String orderId; + + public OrderShippedEvent(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderShippedEvent other = (OrderShippedEvent) obj; + return Objects.equals(this.orderId, other.orderId); + } + + @Override + public String toString() { + return "OrderShippedEvent{" + + "orderId='" + orderId + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java new file mode 100644 index 0000000000..9d6ca2cfb2 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java @@ -0,0 +1,5 @@ +package com.baeldung.axon.coreapi.queries; + +public class FindAllOrderedProductsQuery { + +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java new file mode 100644 index 0000000000..d215c5fc32 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java @@ -0,0 +1,7 @@ +package com.baeldung.axon.coreapi.queries; + +public enum OrderStatus { + + PLACED, CONFIRMED, SHIPPED + +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java new file mode 100644 index 0000000000..d847bb2a98 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java @@ -0,0 +1,64 @@ +package com.baeldung.axon.coreapi.queries; + +import java.util.Objects; + +public class OrderedProduct { + + private final String orderId; + private final String product; + private OrderStatus orderStatus; + + public OrderedProduct(String orderId, String product) { + this.orderId = orderId; + this.product = product; + orderStatus = OrderStatus.PLACED; + } + + public String getOrderId() { + return orderId; + } + + public String getProduct() { + return product; + } + + public OrderStatus getOrderStatus() { + return orderStatus; + } + + public void setOrderConfirmed() { + this.orderStatus = OrderStatus.CONFIRMED; + } + + public void setOrderShipped() { + this.orderStatus = OrderStatus.SHIPPED; + } + + @Override + public int hashCode() { + return Objects.hash(orderId, product, orderStatus); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderedProduct other = (OrderedProduct) obj; + return Objects.equals(this.orderId, other.orderId) + && Objects.equals(this.product, other.product) + && Objects.equals(this.orderStatus, other.orderStatus); + } + + @Override + public String toString() { + return "OrderedProduct{" + + "orderId='" + orderId + '\'' + + ", product='" + product + '\'' + + ", orderStatus=" + orderStatus + + '}'; + } +} diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java deleted file mode 100644 index 3e51e19c4e..0000000000 --- a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.baeldung.axon.eventhandlers; - -import com.baeldung.axon.events.MessageReadEvent; -import com.baeldung.axon.events.MessageCreatedEvent; -import org.axonframework.eventhandling.EventHandler; - - -public class MessagesEventHandler { - - @EventHandler - public void handle(MessageCreatedEvent event) { - System.out.println("Message received: " + event.getText() + " (" + event.getId() + ")"); - } - - @EventHandler - public void handle(MessageReadEvent event) { - System.out.println("Message read: " + event.getId()); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java deleted file mode 100644 index 3c9aac5ed8..0000000000 --- a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.baeldung.axon.events; - -public class MessageCreatedEvent { - - private final String id; - private final String text; - - public MessageCreatedEvent(String id, String text) { - this.id = id; - this.text = text; - } - - public String getId() { - return id; - } - - public String getText() { - return text; - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java deleted file mode 100644 index 57bfc8e19e..0000000000 --- a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.baeldung.axon.events; - -public class MessageReadEvent { - - private final String id; - - public MessageReadEvent(String id) { - this.id = id; - } - - public String getId() { - return id; - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java new file mode 100644 index 0000000000..a9f34cc691 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -0,0 +1,52 @@ +package com.baeldung.axon.gui; + +import java.util.List; +import java.util.UUID; + +import org.axonframework.commandhandling.gateway.CommandGateway; +import org.axonframework.messaging.responsetypes.ResponseTypes; +import org.axonframework.queryhandling.QueryGateway; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +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.queries.FindAllOrderedProductsQuery; +import com.baeldung.axon.coreapi.queries.OrderedProduct; + +@RestController +public class OrderRestEndpoint { + + private final CommandGateway commandGateway; + private final QueryGateway queryGateway; + + public OrderRestEndpoint(CommandGateway commandGateway, QueryGateway queryGateway) { + this.commandGateway = commandGateway; + this.queryGateway = queryGateway; + } + + @PostMapping("/ship-order") + public void shipOrder() { + String orderId = UUID.randomUUID().toString(); + commandGateway.send(new PlaceOrderCommand(orderId, "Deluxe Chair")); + commandGateway.send(new ConfirmOrderCommand(orderId)); + commandGateway.send(new ShipOrderCommand(orderId)); + } + + @PostMapping("/ship-unconfirmed-order") + public void shipUnconfirmedOrder() { + String orderId = UUID.randomUUID().toString(); + commandGateway.send(new PlaceOrderCommand(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)); + } + + @GetMapping("/all-orders") + public List findAllOrderedProducts() { + return queryGateway.query(new FindAllOrderedProductsQuery(), ResponseTypes.multipleInstancesOf(OrderedProduct.class)) + .join(); + } + +} diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java new file mode 100644 index 0000000000..d4cf3d999b --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -0,0 +1,50 @@ +package com.baeldung.axon.querymodel; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.axonframework.eventhandling.EventHandler; +import org.axonframework.queryhandling.QueryHandler; +import org.springframework.stereotype.Service; + +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.queries.FindAllOrderedProductsQuery; +import com.baeldung.axon.coreapi.queries.OrderedProduct; + +@Service +public class OrderedProductsEventHandler { + + private final Map orderedProducts = new HashMap<>(); + + @EventHandler + public void on(OrderPlacedEvent event) { + String orderId = event.getOrderId(); + orderedProducts.put(orderId, new OrderedProduct(orderId, event.getProduct())); + } + + @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 handle(FindAllOrderedProductsQuery query) { + return new ArrayList<>(orderedProducts.values()); + } + +} \ No newline at end of file diff --git a/axon/src/main/resources/order-api.http b/axon/src/main/resources/order-api.http new file mode 100644 index 0000000000..a3c69c72bc --- /dev/null +++ b/axon/src/main/resources/order-api.http @@ -0,0 +1,11 @@ +POST http://localhost:8080/ship-order + +### + +POST http://localhost:8080/ship-unconfirmed-order + +### + +GET http://localhost:8080/all-orders + +### diff --git a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java deleted file mode 100644 index ad099d2c2b..0000000000 --- a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.axon; - -import com.baeldung.axon.aggregates.MessagesAggregate; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; -import org.axonframework.test.aggregate.AggregateTestFixture; -import org.axonframework.test.aggregate.FixtureConfiguration; -import org.junit.Before; -import org.junit.Test; - -import java.util.UUID; - -public class MessagesAggregateIntegrationTest { - - private FixtureConfiguration fixture; - - @Before - public void setUp() throws Exception { - fixture = new AggregateTestFixture(MessagesAggregate.class); - - } - - @Test - public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() throws Exception { - String eventText = "Hello, how is your day?"; - String id = UUID.randomUUID().toString(); - fixture.given() - .when(new CreateMessageCommand(id, eventText)) - .expectEvents(new MessageCreatedEvent(id, eventText)); - } - - @Test - public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() throws Exception { - String id = UUID.randomUUID().toString(); - - fixture.given(new MessageCreatedEvent(id, "Hello :-)")) - .when(new MarkReadMessageCommand(id)) - .expectEvents(new MessageReadEvent(id)); - } -} \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java new file mode 100644 index 0000000000..9beedbaa19 --- /dev/null +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.axon.commandmodel; + +import java.util.UUID; + +import org.axonframework.test.aggregate.AggregateTestFixture; +import org.axonframework.test.aggregate.FixtureConfiguration; +import org.junit.*; + +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; + +public class OrderAggregateUnitTest { + + private FixtureConfiguration fixture; + + @Before + public void setUp() { + fixture = new AggregateTestFixture<>(OrderAggregate.class); + } + + @Test + public void giveNoPriorActivity_whenPlaceOrderCommand_thenShouldPublishOrderPlacedEvent() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.givenNoPriorActivity() + .when(new PlaceOrderCommand(orderId, product)) + .expectEvents(new OrderPlacedEvent(orderId, product)); + } + + @Test + public void givenOrderPlacedEvent_whenConfirmOrderCommand_thenShouldPublishOrderConfirmedEvent() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.given(new OrderPlacedEvent(orderId, product)) + .when(new ConfirmOrderCommand(orderId)) + .expectEvents(new OrderConfirmedEvent(orderId)); + } + + @Test + public void givenOrderPlacedEvent_whenShipOrderCommand_thenShouldThrowIllegalStateException() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.given(new OrderPlacedEvent(orderId, product)) + .when(new ShipOrderCommand(orderId)) + .expectException(IllegalStateException.class); + } + + @Test + public void givenOrderPlacedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.given(new OrderPlacedEvent(orderId, product), new OrderConfirmedEvent(orderId)) + .when(new ShipOrderCommand(orderId)) + .expectEvents(new OrderShippedEvent(orderId)); + } + +} \ No newline at end of file