From cf56b33b9bc2890f419e529ffd37dea4ec5c38ae Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:43:32 +0100 Subject: [PATCH 01/22] BAEL-2435 Update pom file -Add description -Change parent to parent-boot-2 to leverage a spring boot start up approach -Replace core dependency for axon-spring-boot-autoconfigure excluding axon-server as we cant start that up for this use case -Add spring-boot-autoconfigure dependency -Adjust the axon version to 4.0.3 --- axon/pom.xml | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/axon/pom.xml b/axon/pom.xml index c643ea9e57..bb7839f150 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -4,29 +4,45 @@ 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-autoconfigure + ${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 - 3.0.2 + 4.0.3 \ No newline at end of file From bd4881d4787cea8ee7f78309e956a7363d14c1b3 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:47:23 +0100 Subject: [PATCH 02/22] BAEL-2435 Update Aggregate in regards to latest axon version -Replace old import statements for the new locations -Mark the aggregate as @Aggregate to make it autowired through the spring boot starter -Move all command handlers/decision making functions to the top of the file -Rename the command handler to `handle` as a best practice for command handlers -Use @EventSourcingHandler i.o. @EventHandler as a best practice for event handlers in Aggregates, as those only are used to 'source' the aggregate -Update test case according to latest standards --- .../axon/aggregates/MessagesAggregate.java | 26 ++++++++++--------- .../MessagesAggregateIntegrationTest.java | 21 +++++++-------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java index e762604b74..d95dd81df9 100644 --- a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java @@ -1,16 +1,18 @@ package com.baeldung.axon.aggregates; +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.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; - +@Aggregate public class MessagesAggregate { @AggregateIdentifier @@ -24,13 +26,13 @@ public class MessagesAggregate { apply(new MessageCreatedEvent(command.getId(), command.getText())); } - @EventHandler + @CommandHandler + public void handle(MarkReadMessageCommand command) { + apply(new MessageReadEvent(id)); + } + + @EventSourcingHandler 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/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java index ad099d2c2b..dc008dcd78 100644 --- a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java @@ -1,29 +1,28 @@ package com.baeldung.axon; +import java.util.UUID; + +import org.axonframework.test.aggregate.AggregateTestFixture; +import org.axonframework.test.aggregate.FixtureConfiguration; +import org.junit.*; + 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); - + public void setUp() { + fixture = new AggregateTestFixture<>(MessagesAggregate.class); } @Test - public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() throws Exception { + public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() { String eventText = "Hello, how is your day?"; String id = UUID.randomUUID().toString(); fixture.given() @@ -32,7 +31,7 @@ public class MessagesAggregateIntegrationTest { } @Test - public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() throws Exception { + public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() { String id = UUID.randomUUID().toString(); fixture.given(new MessageCreatedEvent(id, "Hello :-)")) From 11b1112771d6327560debdf0c06306103c5bf7ac Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:48:10 +0100 Subject: [PATCH 03/22] BAEL-2435 Update the event handler Change the event handler to become a spring service, as this way Axon will automatically pick it up as an event handling component --- .../baeldung/axon/eventhandlers/MessagesEventHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java index 3e51e19c4e..d7ac115a16 100644 --- a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java @@ -1,10 +1,12 @@ package com.baeldung.axon.eventhandlers; -import com.baeldung.axon.events.MessageReadEvent; -import com.baeldung.axon.events.MessageCreatedEvent; import org.axonframework.eventhandling.EventHandler; +import org.springframework.stereotype.Service; +import com.baeldung.axon.events.MessageCreatedEvent; +import com.baeldung.axon.events.MessageReadEvent; +@Service public class MessagesEventHandler { @EventHandler From 3553fb750685f94af4f8dbdeaffb0a140497556a Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:49:30 +0100 Subject: [PATCH 04/22] BAEL-2435 Update commands and events -Change TargetAggregateIdentifier import statement to the new location -Add equals/hashcode as best practice for commands and events -Add description -Change parent to parent-boot-2 to leverage a spring boot start up approach --- .../axon/commands/CreateMessageCommand.java | 28 +++++++++++++++---- .../axon/commands/MarkReadMessageCommand.java | 26 ++++++++++++++--- .../axon/events/MessageCreatedEvent.java | 27 +++++++++++++++--- .../axon/events/MessageReadEvent.java | 25 +++++++++++++++-- 4 files changed, 90 insertions(+), 16 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java index d0651bf12e..70d2e46480 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java @@ -1,24 +1,42 @@ package com.baeldung.axon.commands; +import java.util.Objects; -import org.axonframework.commandhandling.TargetAggregateIdentifier; +import org.axonframework.modelling.command.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; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CreateMessageCommand that = (CreateMessageCommand) o; + return Objects.equals(id, that.id) && Objects.equals(text, that.text); + } + + @Override + public int hashCode() { + return Objects.hash(id, 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 index e66582d9ec..f7d911d65b 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java @@ -1,18 +1,36 @@ package com.baeldung.axon.commands; +import java.util.Objects; -import org.axonframework.commandhandling.TargetAggregateIdentifier; +import org.axonframework.modelling.command.TargetAggregateIdentifier; public class MarkReadMessageCommand { - + @TargetAggregateIdentifier private final String id; - + public MarkReadMessageCommand(String id) { this.id = id; } - + public String getId() { return id; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MarkReadMessageCommand that = (MarkReadMessageCommand) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } \ 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 index 3c9aac5ed8..e638a2a94d 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java @@ -1,20 +1,39 @@ package com.baeldung.axon.events; +import java.util.Objects; + 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; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MessageCreatedEvent that = (MessageCreatedEvent) o; + return Objects.equals(id, that.id) && Objects.equals(text, that.text); + } + + @Override + public int hashCode() { + return Objects.hash(id, 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 index 57bfc8e19e..e362599bb3 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java +++ b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java @@ -1,14 +1,33 @@ package com.baeldung.axon.events; +import java.util.Objects; + public class MessageReadEvent { - + private final String id; - + public MessageReadEvent(String id) { this.id = id; } - + public String getId() { return id; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MessageReadEvent that = (MessageReadEvent) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } \ No newline at end of file From 3e3210a8038b4c9453d1958714119243d0c732d3 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:52:54 +0100 Subject: [PATCH 05/22] BAEL-2435 Change aggregate package -Change aggregate package to commandmodel package per best practice -Move the aggregate test to the same package for the test directory --- .../axon/{aggregates => commandmodel}/MessagesAggregate.java | 2 +- .../{ => commandmodel}/MessagesAggregateIntegrationTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename axon/src/main/java/com/baeldung/axon/{aggregates => commandmodel}/MessagesAggregate.java (96%) rename axon/src/test/java/com/baeldung/axon/{ => commandmodel}/MessagesAggregateIntegrationTest.java (94%) diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java similarity index 96% rename from axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java rename to axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java index d95dd81df9..b2c3a0a0b6 100644 --- a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.aggregates; +package com.baeldung.axon.commandmodel; import static org.axonframework.modelling.command.AggregateLifecycle.apply; diff --git a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java similarity index 94% rename from axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java rename to axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java index dc008dcd78..96bb2cf3b7 100644 --- a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.axon; +package com.baeldung.axon.commandmodel; import java.util.UUID; @@ -6,7 +6,6 @@ import org.axonframework.test.aggregate.AggregateTestFixture; import org.axonframework.test.aggregate.FixtureConfiguration; import org.junit.*; -import com.baeldung.axon.aggregates.MessagesAggregate; import com.baeldung.axon.commands.CreateMessageCommand; import com.baeldung.axon.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; From 00b297a4d0a21282d13b7c7a41544aa56b782b59 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:53:43 +0100 Subject: [PATCH 06/22] BAEL-2435 Rename aggregate test Rename aggregate test from MessagesAggregateIntegrationTest to MessagesAggregateTest, as it's not an integration test but a regular unit test --- ...AggregateIntegrationTest.java => MessagesAggregateTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename axon/src/test/java/com/baeldung/axon/commandmodel/{MessagesAggregateIntegrationTest.java => MessagesAggregateTest.java} (96%) diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java similarity index 96% rename from axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java rename to axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java index 96bb2cf3b7..30914e3fd3 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java @@ -11,7 +11,7 @@ import com.baeldung.axon.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; -public class MessagesAggregateIntegrationTest { +public class MessagesAggregateTest { private FixtureConfiguration fixture; From aaf2ef22276bc1b3f0bc64f3acbf0d3582afb9c9 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:54:07 +0100 Subject: [PATCH 07/22] BAEL-2435 Change eventhandlers package Change eventhandlers package to querymodel package per best practices --- .../{eventhandlers => querymodel}/MessagesEventHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename axon/src/main/java/com/baeldung/axon/{eventhandlers => querymodel}/MessagesEventHandler.java (93%) diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java similarity index 93% rename from axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java rename to axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java index d7ac115a16..d93fe03941 100644 --- a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.eventhandlers; +package com.baeldung.axon.querymodel; import org.axonframework.eventhandling.EventHandler; import org.springframework.stereotype.Service; From 96945027a14e5bf1a9b72ddfac7e38e1c170af74 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:55:28 +0100 Subject: [PATCH 08/22] BAEL-2435 Change command message package Change the package of the command messages to coreapi.commands to signal that the commands are part of the API you'd share with the outside --- .../com/baeldung/axon/commandmodel/MessagesAggregate.java | 4 ++-- .../axon/{ => coreapi}/commands/CreateMessageCommand.java | 2 +- .../axon/{ => coreapi}/commands/MarkReadMessageCommand.java | 2 +- .../com/baeldung/axon/commandmodel/MessagesAggregateTest.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/commands/CreateMessageCommand.java (95%) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/commands/MarkReadMessageCommand.java (94%) diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java index b2c3a0a0b6..60b5c7c94e 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java @@ -7,8 +7,8 @@ import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.AggregateIdentifier; import org.axonframework.spring.stereotype.Aggregate; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.coreapi.commands.CreateMessageCommand; +import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java similarity index 95% rename from axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java rename to axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java index 70d2e46480..fd03d6b269 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.commands; +package com.baeldung.axon.coreapi.commands; import java.util.Objects; diff --git a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java similarity index 94% rename from axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java rename to axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java index f7d911d65b..ec68a380f8 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.commands; +package com.baeldung.axon.coreapi.commands; import java.util.Objects; diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java index 30914e3fd3..3bb7fdc9a2 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java @@ -6,8 +6,8 @@ import org.axonframework.test.aggregate.AggregateTestFixture; import org.axonframework.test.aggregate.FixtureConfiguration; import org.junit.*; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.coreapi.commands.CreateMessageCommand; +import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; From 2b07c0364d5f7cd1e4d8f178bd99c968e89324c2 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:56:23 +0100 Subject: [PATCH 09/22] BAEL-2435 Change event message package Change the package of the event messages to coreapi.events to signal that the events are part of the API you'd share with the outside --- .../com/baeldung/axon/commandmodel/MessagesAggregate.java | 4 ++-- .../axon/{ => coreapi}/events/MessageCreatedEvent.java | 2 +- .../baeldung/axon/{ => coreapi}/events/MessageReadEvent.java | 2 +- .../com/baeldung/axon/querymodel/MessagesEventHandler.java | 4 ++-- .../com/baeldung/axon/commandmodel/MessagesAggregateTest.java | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/events/MessageCreatedEvent.java (94%) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/events/MessageReadEvent.java (93%) diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java index 60b5c7c94e..1ab9501617 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java @@ -9,8 +9,8 @@ import org.axonframework.spring.stereotype.Aggregate; import com.baeldung.axon.coreapi.commands.CreateMessageCommand; import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.coreapi.events.MessageCreatedEvent; +import com.baeldung.axon.coreapi.events.MessageReadEvent; @Aggregate public class MessagesAggregate { diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java similarity index 94% rename from axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java rename to axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java index e638a2a94d..debf383771 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.events; +package com.baeldung.axon.coreapi.events; import java.util.Objects; diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java similarity index 93% rename from axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java rename to axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java index e362599bb3..f90bfb054e 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.events; +package com.baeldung.axon.coreapi.events; import java.util.Objects; diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java index d93fe03941..6988d40a53 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java @@ -3,8 +3,8 @@ package com.baeldung.axon.querymodel; import org.axonframework.eventhandling.EventHandler; import org.springframework.stereotype.Service; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.coreapi.events.MessageCreatedEvent; +import com.baeldung.axon.coreapi.events.MessageReadEvent; @Service public class MessagesEventHandler { diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java index 3bb7fdc9a2..1a95726c83 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java @@ -8,8 +8,8 @@ import org.junit.*; import com.baeldung.axon.coreapi.commands.CreateMessageCommand; import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.coreapi.events.MessageCreatedEvent; +import com.baeldung.axon.coreapi.events.MessageReadEvent; public class MessagesAggregateTest { From e731b95ffbb596d3674bd3e6de724e35dcf4a7df Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:01:29 +0100 Subject: [PATCH 10/22] BAEL-2435 Rename unit test class Rename unit test class to actual contain 'UnitTest' per the defined standards --- ...essagesAggregateTest.java => MessagesAggregateUnitTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename axon/src/test/java/com/baeldung/axon/commandmodel/{MessagesAggregateTest.java => MessagesAggregateUnitTest.java} (97%) diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java similarity index 97% rename from axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java rename to axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java index 1a95726c83..46357ddff8 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java @@ -11,7 +11,7 @@ import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; import com.baeldung.axon.coreapi.events.MessageCreatedEvent; import com.baeldung.axon.coreapi.events.MessageReadEvent; -public class MessagesAggregateTest { +public class MessagesAggregateUnitTest { private FixtureConfiguration fixture; From fe30c44889111ccaa94b4e69d49fc800b21c5d90 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:15:23 +0100 Subject: [PATCH 11/22] BAEL-2435 Add a GUI -Add spring-boot-starter-web to support rest endpoints -Add a rest endpoint to spoof some form of UI to publish a message, as the old main will no longer publish the commands upon start up --- axon/pom.xml | 5 ++++ .../axon/gui/MessagesRestEndpoint.java | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java diff --git a/axon/pom.xml b/axon/pom.xml index bb7839f150..639c50d70b 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -39,6 +39,11 @@ 2.1.1.RELEASE compile + + + org.springframework.boot + spring-boot-starter-web + diff --git a/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java new file mode 100644 index 0000000000..ddbc3e2fc5 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java @@ -0,0 +1,28 @@ +package com.baeldung.axon.gui; + +import java.util.UUID; + +import org.axonframework.commandhandling.gateway.CommandGateway; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.axon.coreapi.commands.CreateMessageCommand; +import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; + +@RestController +public class MessagesRestEndpoint { + + private final CommandGateway commandGateway; + + public MessagesRestEndpoint(CommandGateway commandGateway) { + this.commandGateway = commandGateway; + } + + @PostMapping("/hello") + public void publishMessages() { + final String itemId = UUID.randomUUID().toString(); + commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); + commandGateway.send(new MarkReadMessageCommand(itemId)); + } + +} From d8ef050867fbf473260f51509ed775a719737879 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:16:31 +0100 Subject: [PATCH 12/22] BAEL-2435 Add JPA and H2 dependencies Add JPA and H2 dependencies to allow event sourcing, as for event sourcing and EventStore is mandatory, and to make an EventStore a database needs to be present for Axon's auto-configuration --- axon/pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/axon/pom.xml b/axon/pom.xml index 639c50d70b..03d2499a99 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -44,6 +44,17 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + From 557ce655522559c849e4a02cdd54955872d700c5 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:17:16 +0100 Subject: [PATCH 13/22] BAEL-2435 Update main application Update the MessagesRunner to be a spring boot application --- .../com/baeldung/axon/MessagesRunner.java | 51 ++----------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java index 77b50d09bd..4f83dd86f0 100644 --- a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java +++ b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java @@ -1,54 +1,13 @@ 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; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +@SpringBootApplication 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)); + SpringApplication.run(MessagesRunner.class, args); } + } \ No newline at end of file From 2279246a426c9d35618ce2a1dc2f26b724922060 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 09:39:40 +0100 Subject: [PATCH 14/22] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. First, update the commands and events, adding an extra command/event to flesh out the domain some what --- .../coreapi/commands/ConfirmOrderCommand.java | 36 ++++++++++++++++ .../commands/CreateMessageCommand.java | 42 ------------------ .../commands/MarkReadMessageCommand.java | 36 ---------------- .../coreapi/commands/PlaceOrderCommand.java | 43 +++++++++++++++++++ .../coreapi/commands/ShipOrderCommand.java | 36 ++++++++++++++++ .../coreapi/events/MessageCreatedEvent.java | 39 ----------------- .../axon/coreapi/events/MessageReadEvent.java | 33 -------------- .../coreapi/events/OrderConfirmedEvent.java | 33 ++++++++++++++ .../axon/coreapi/events/OrderPlacedEvent.java | 40 +++++++++++++++++ .../coreapi/events/OrderShippedEvent.java | 33 ++++++++++++++ 10 files changed, 221 insertions(+), 150 deletions(-) create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java 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..ba04343af1 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java @@ -0,0 +1,36 @@ +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); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java deleted file mode 100644 index fd03d6b269..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.axon.coreapi.commands; - -import java.util.Objects; - -import org.axonframework.modelling.command.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; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateMessageCommand that = (CreateMessageCommand) o; - return Objects.equals(id, that.id) && Objects.equals(text, that.text); - } - - @Override - public int hashCode() { - return Objects.hash(id, text); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java deleted file mode 100644 index ec68a380f8..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.axon.coreapi.commands; - -import java.util.Objects; - -import org.axonframework.modelling.command.TargetAggregateIdentifier; - -public class MarkReadMessageCommand { - - @TargetAggregateIdentifier - private final String id; - - public MarkReadMessageCommand(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MarkReadMessageCommand that = (MarkReadMessageCommand) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} \ No newline at end of file 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..cde2d7f1ae --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java @@ -0,0 +1,43 @@ +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); + } +} \ 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..75469533b9 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java @@ -0,0 +1,36 @@ +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); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java deleted file mode 100644 index debf383771..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.baeldung.axon.coreapi.events; - -import java.util.Objects; - -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; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MessageCreatedEvent that = (MessageCreatedEvent) o; - return Objects.equals(id, that.id) && Objects.equals(text, that.text); - } - - @Override - public int hashCode() { - return Objects.hash(id, text); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java deleted file mode 100644 index f90bfb054e..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.axon.coreapi.events; - -import java.util.Objects; - -public class MessageReadEvent { - - private final String id; - - public MessageReadEvent(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MessageReadEvent that = (MessageReadEvent) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} \ 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..1706b08023 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java @@ -0,0 +1,33 @@ +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); + } +} 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..8d5364f4c6 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java @@ -0,0 +1,40 @@ +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); + } +} \ 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..5abcd09a3c --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java @@ -0,0 +1,33 @@ +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); + } +} \ No newline at end of file From bd0a1efe707ba65b04f21a21f621110b7769ab0a Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 09:51:08 +0100 Subject: [PATCH 15/22] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. To that end the MessagesAggregate should be replaced by an OrderAggregate. Additionally, add some decision making logic which denies the shipping of an order if it hasn't been confirmed yet. Adjust and update thee unit test accordingly --- .../axon/commandmodel/MessagesAggregate.java | 38 ------------ .../axon/commandmodel/OrderAggregate.java | 58 +++++++++++++++++++ .../MessagesAggregateUnitTest.java | 40 ------------- .../commandmodel/OrderAggregateUnitTest.java | 48 +++++++++++++++ 4 files changed, 106 insertions(+), 78 deletions(-) delete mode 100644 axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java create mode 100644 axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java delete mode 100644 axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java create mode 100644 axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java deleted file mode 100644 index 1ab9501617..0000000000 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java +++ /dev/null @@ -1,38 +0,0 @@ -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.CreateMessageCommand; -import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.coreapi.events.MessageCreatedEvent; -import com.baeldung.axon.coreapi.events.MessageReadEvent; - -@Aggregate -public class MessagesAggregate { - - @AggregateIdentifier - private String id; - - public MessagesAggregate() { - } - - @CommandHandler - public MessagesAggregate(CreateMessageCommand command) { - apply(new MessageCreatedEvent(command.getId(), command.getText())); - } - - @CommandHandler - public void handle(MarkReadMessageCommand command) { - apply(new MessageReadEvent(id)); - } - - @EventSourcingHandler - public void on(MessageCreatedEvent event) { - this.id = event.getId(); - } -} \ 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..fd4f901032 --- /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 ben 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/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java deleted file mode 100644 index 46357ddff8..0000000000 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -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.CreateMessageCommand; -import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.coreapi.events.MessageCreatedEvent; -import com.baeldung.axon.coreapi.events.MessageReadEvent; - -public class MessagesAggregateUnitTest { - - private FixtureConfiguration fixture; - - @Before - public void setUp() { - fixture = new AggregateTestFixture<>(MessagesAggregate.class); - } - - @Test - public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() { - 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() { - 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..e7dfdeb794 --- /dev/null +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java @@ -0,0 +1,48 @@ +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.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 static final String ORDER_ID = UUID.randomUUID().toString(); + private static final String DEFAULT_PRODUCT = "Deluxe Chair"; + + private FixtureConfiguration fixture; + + @Before + public void setUp() { + fixture = new AggregateTestFixture<>(OrderAggregate.class); + } + + @Test + public void giveNoPriorActivity_whenPlaceOrderCommand_thenShouldPublishOrderPlacedEvent() { + fixture.givenNoPriorActivity() + .when(new PlaceOrderCommand(ORDER_ID, DEFAULT_PRODUCT)) + .expectEvents(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)); + } + + @Test + public void givenOrderPlacedEvent_whenShipOrderCommand_thenShouldThrowIllegalStateException() { + fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)) + .when(new ShipOrderCommand(ORDER_ID)) + .expectException(IllegalStateException.class); + } + + @Test + public void givenOrderPlacedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() { + fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT), new OrderConfirmedEvent(ORDER_ID)) + .when(new ShipOrderCommand(ORDER_ID)) + .expectEvents(new OrderShippedEvent(ORDER_ID)); + } + +} \ No newline at end of file From eab6dfe0dd5e29afd990f7b3770242c93d1f3d01 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 09:55:49 +0100 Subject: [PATCH 16/22] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. Update the endpoint to reflect the order focus i.o. the message focus. Additionally, add a POST endpoint which would return an exception due to the state check in the aggregate --- .../axon/gui/MessagesRestEndpoint.java | 28 ------------- .../baeldung/axon/gui/OrderRestEndpoint.java | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 28 deletions(-) delete mode 100644 axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java create mode 100644 axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java diff --git a/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java deleted file mode 100644 index ddbc3e2fc5..0000000000 --- a/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.axon.gui; - -import java.util.UUID; - -import org.axonframework.commandhandling.gateway.CommandGateway; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.baeldung.axon.coreapi.commands.CreateMessageCommand; -import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; - -@RestController -public class MessagesRestEndpoint { - - private final CommandGateway commandGateway; - - public MessagesRestEndpoint(CommandGateway commandGateway) { - this.commandGateway = commandGateway; - } - - @PostMapping("/hello") - public void publishMessages() { - final String itemId = UUID.randomUUID().toString(); - commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); - commandGateway.send(new MarkReadMessageCommand(itemId)); - } - -} 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..3c86f9c3b1 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -0,0 +1,40 @@ +package com.baeldung.axon.gui; + +import java.util.UUID; + +import org.axonframework.commandhandling.gateway.CommandGateway; +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; + +@RestController +public class OrderRestEndpoint { + + private static final String DEFAULT_PRODUCT = "Deluxe Chair"; + + private final CommandGateway commandGateway; + + public OrderRestEndpoint(CommandGateway commandGateway) { + this.commandGateway = commandGateway; + } + + @PostMapping("/ship-order") + public void shipOrder() { + String orderId = UUID.randomUUID().toString(); + commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + 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, DEFAULT_PRODUCT)); + // This throws an exception, as an Order cannot be shipped if it has not been confirmed yet. + commandGateway.send(new ShipOrderCommand(orderId)); + } + +} From 84b6dc1dbb7badacaed4bbcc5a889ba5a1d5171c Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:36:10 +0100 Subject: [PATCH 17/22] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. The Query Model would be better suited to revolve around the OrderedProducts rather than just printing out a line of text. To that end, add a OrderedProduct model with the OrderStatus, which is updated in the (renamed) OrderedProductsEventHandler upon all the events --- .../axon/coreapi/queries/OrderStatus.java | 7 +++ .../axon/coreapi/queries/OrderedProduct.java | 55 +++++++++++++++++++ .../axon/querymodel/MessagesEventHandler.java | 21 ------- .../OrderedProductsEventHandler.java | 42 ++++++++++++++ 4 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java delete mode 100644 axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java create mode 100644 axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java 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..25096eeb42 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java @@ -0,0 +1,55 @@ +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); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java deleted file mode 100644 index 6988d40a53..0000000000 --- a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.baeldung.axon.querymodel; - -import org.axonframework.eventhandling.EventHandler; -import org.springframework.stereotype.Service; - -import com.baeldung.axon.coreapi.events.MessageCreatedEvent; -import com.baeldung.axon.coreapi.events.MessageReadEvent; - -@Service -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/querymodel/OrderedProductsEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java new file mode 100644 index 0000000000..7bcdb27af7 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -0,0 +1,42 @@ +package com.baeldung.axon.querymodel; + +import java.util.HashMap; +import java.util.Map; + +import org.axonframework.eventhandling.EventHandler; +import org.springframework.stereotype.Service; + +import com.baeldung.axon.coreapi.queries.OrderedProduct; +import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; +import com.baeldung.axon.coreapi.events.OrderPlacedEvent; +import com.baeldung.axon.coreapi.events.OrderShippedEvent; + +@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(OrderShippedEvent event) { + orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { + orderedProduct.setOrderShipped(); + return orderedProduct; + }); + } + + @EventHandler + public void on(OrderConfirmedEvent event) { + orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { + orderedProduct.setOrderConfirmed(); + return orderedProduct; + }); + } + +} \ No newline at end of file From 769af6759ed6dca02d6c8732f2627e11e5f66a48 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:39:42 +0100 Subject: [PATCH 18/22] BAEL-2435 Introduce Query message logic Introduce a FindAllOrderedProductsQuery query message, which is published on the QueryGateway through the OrderRestEndpoint and handled by the OrderedProductsEventHandler --- .../queries/FindAllOrderedProductsQuery.java | 5 +++++ .../com/baeldung/axon/gui/OrderRestEndpoint.java | 16 +++++++++++++++- .../querymodel/OrderedProductsEventHandler.java | 11 ++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java 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/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java index 3c86f9c3b1..3b8be0bc46 100644 --- a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -1,14 +1,20 @@ 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 { @@ -16,9 +22,11 @@ public class OrderRestEndpoint { private static final String DEFAULT_PRODUCT = "Deluxe Chair"; private final CommandGateway commandGateway; + private final QueryGateway queryGateway; - public OrderRestEndpoint(CommandGateway commandGateway) { + public OrderRestEndpoint(CommandGateway commandGateway, QueryGateway queryGateway) { this.commandGateway = commandGateway; + this.queryGateway = queryGateway; } @PostMapping("/ship-order") @@ -37,4 +45,10 @@ public class OrderRestEndpoint { 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 index 7bcdb27af7..c2bf48614b 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -1,15 +1,19 @@ 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.queries.OrderedProduct; 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 { @@ -39,4 +43,9 @@ public class OrderedProductsEventHandler { }); } + @QueryHandler + public List handle(FindAllOrderedProductsQuery query) { + return new ArrayList<>(orderedProducts.values()); + } + } \ No newline at end of file From 4c7303c2936706da2aa207eae4b41f0caf8f9d19 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:46:45 +0100 Subject: [PATCH 19/22] BAEL-2435 Rename main file Rename main file from MessagesRunner to OrderApplication --- .../axon/{MessagesRunner.java => OrderApplication.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename axon/src/main/java/com/baeldung/axon/{MessagesRunner.java => OrderApplication.java} (70%) diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/OrderApplication.java similarity index 70% rename from axon/src/main/java/com/baeldung/axon/MessagesRunner.java rename to axon/src/main/java/com/baeldung/axon/OrderApplication.java index 4f83dd86f0..8f507e141c 100644 --- a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java +++ b/axon/src/main/java/com/baeldung/axon/OrderApplication.java @@ -4,10 +4,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class MessagesRunner { +public class OrderApplication { public static void main(String[] args) { - SpringApplication.run(MessagesRunner.class, args); + SpringApplication.run(OrderApplication.class, args); } } \ No newline at end of file From d5ad67a801d96ba707729c0dcb87e331eef5ae28 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:47:22 +0100 Subject: [PATCH 20/22] BAEL-2435 Add http resource Add http resource to try out all the end points when running the application in Intellij --- axon/src/main/resources/order-api.http | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 axon/src/main/resources/order-api.http 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 + +### From 03306112bdc117277afa828912a81b5fe938d158 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Fri, 28 Dec 2018 15:58:41 +0100 Subject: [PATCH 21/22] BAEL-2435 Minor clean ups -Add toString() function to messages/query-model -Fix typo in exception -Reorder event handlers in OrderedProductsEventHandler -Replace usage of constants for local fields -Add missing Aggregate test case --- .../axon/commandmodel/OrderAggregate.java | 2 +- .../coreapi/commands/ConfirmOrderCommand.java | 7 ++++ .../coreapi/commands/PlaceOrderCommand.java | 8 +++++ .../coreapi/commands/ShipOrderCommand.java | 7 ++++ .../coreapi/events/OrderConfirmedEvent.java | 7 ++++ .../axon/coreapi/events/OrderPlacedEvent.java | 8 +++++ .../coreapi/events/OrderShippedEvent.java | 7 ++++ .../axon/coreapi/queries/OrderedProduct.java | 9 +++++ .../baeldung/axon/gui/OrderRestEndpoint.java | 8 ++--- .../OrderedProductsEventHandler.java | 17 +++++----- .../commandmodel/OrderAggregateUnitTest.java | 33 +++++++++++++------ 11 files changed, 88 insertions(+), 25 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java index fd4f901032..b37b2fdd66 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java @@ -34,7 +34,7 @@ public class OrderAggregate { @CommandHandler public void handle(ShipOrderCommand command) { if (!orderConfirmed) { - throw new IllegalStateException("Cannot ship an order which has not ben confirmed yet."); + throw new IllegalStateException("Cannot ship an order which has not been confirmed yet."); } apply(new OrderShippedEvent(orderId)); 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 index ba04343af1..244b69f3b7 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java @@ -33,4 +33,11 @@ public class ConfirmOrderCommand { 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 index cde2d7f1ae..c70d503050 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java @@ -40,4 +40,12 @@ public class PlaceOrderCommand { 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 index 75469533b9..7312bc1fdb 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java @@ -33,4 +33,11 @@ public class ShipOrderCommand { 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 index 1706b08023..d2b7d58435 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java @@ -30,4 +30,11 @@ public class OrderConfirmedEvent { 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 index 8d5364f4c6..06de4c5f9f 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java @@ -37,4 +37,12 @@ public class OrderPlacedEvent { 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 index 5abcd09a3c..76aa684629 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java @@ -30,4 +30,11 @@ public class OrderShippedEvent { 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/OrderedProduct.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java index 25096eeb42..d847bb2a98 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java @@ -52,4 +52,13 @@ public class OrderedProduct { && 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/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java index 3b8be0bc46..a9f34cc691 100644 --- a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -19,8 +19,6 @@ import com.baeldung.axon.coreapi.queries.OrderedProduct; @RestController public class OrderRestEndpoint { - private static final String DEFAULT_PRODUCT = "Deluxe Chair"; - private final CommandGateway commandGateway; private final QueryGateway queryGateway; @@ -32,7 +30,7 @@ public class OrderRestEndpoint { @PostMapping("/ship-order") public void shipOrder() { String orderId = UUID.randomUUID().toString(); - commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + commandGateway.send(new PlaceOrderCommand(orderId, "Deluxe Chair")); commandGateway.send(new ConfirmOrderCommand(orderId)); commandGateway.send(new ShipOrderCommand(orderId)); } @@ -40,7 +38,7 @@ public class OrderRestEndpoint { @PostMapping("/ship-unconfirmed-order") public void shipUnconfirmedOrder() { String orderId = UUID.randomUUID().toString(); - commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + 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)); } @@ -48,7 +46,7 @@ public class OrderRestEndpoint { @GetMapping("/all-orders") public List findAllOrderedProducts() { return queryGateway.query(new FindAllOrderedProductsQuery(), ResponseTypes.multipleInstancesOf(OrderedProduct.class)) - .join(); + .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 index c2bf48614b..d4cf3d999b 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -24,15 +24,6 @@ public class OrderedProductsEventHandler { public void on(OrderPlacedEvent event) { String orderId = event.getOrderId(); orderedProducts.put(orderId, new OrderedProduct(orderId, event.getProduct())); - - } - - @EventHandler - public void on(OrderShippedEvent event) { - orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { - orderedProduct.setOrderShipped(); - return orderedProduct; - }); } @EventHandler @@ -43,6 +34,14 @@ public class OrderedProductsEventHandler { }); } + @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()); diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java index e7dfdeb794..9beedbaa19 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java @@ -6,6 +6,7 @@ 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; @@ -14,9 +15,6 @@ import com.baeldung.axon.coreapi.events.OrderShippedEvent; public class OrderAggregateUnitTest { - private static final String ORDER_ID = UUID.randomUUID().toString(); - private static final String DEFAULT_PRODUCT = "Deluxe Chair"; - private FixtureConfiguration fixture; @Before @@ -26,23 +24,38 @@ public class OrderAggregateUnitTest { @Test public void giveNoPriorActivity_whenPlaceOrderCommand_thenShouldPublishOrderPlacedEvent() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; fixture.givenNoPriorActivity() - .when(new PlaceOrderCommand(ORDER_ID, DEFAULT_PRODUCT)) - .expectEvents(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)); + .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() { - fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)) - .when(new ShipOrderCommand(ORDER_ID)) + 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() { - fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT), new OrderConfirmedEvent(ORDER_ID)) - .when(new ShipOrderCommand(ORDER_ID)) - .expectEvents(new OrderShippedEvent(ORDER_ID)); + 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 From 0cf67f5dbef3d8c1ef17d2478654469f17fb2472 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Mon, 31 Dec 2018 13:45:58 +0100 Subject: [PATCH 22/22] BAEL-2435 Change dependency Change the autoconfigure dependency to the starter dependency of Axon --- axon/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axon/pom.xml b/axon/pom.xml index 03d2499a99..598dc820e5 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -16,7 +16,7 @@ org.axonframework - axon-spring-boot-autoconfigure + axon-spring-boot-starter ${axon.version}