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