Permalink
Browse files

started implementing implementing saga's

  • Loading branch information...
1 parent d010518 commit 5974299fdaeb807d0d781967c9bf285dc2f3cca4 @jettro jettro committed Nov 29, 2011
@@ -24,12 +24,12 @@
public abstract class AbstractTransactionStartedEvent extends DomainEvent {
private AggregateIdentifier orderbookIdentifier;
private AggregateIdentifier portfolioIdentifier;
- private long totalItems;
+ private int totalItems;
private long pricePerItem;
public AbstractTransactionStartedEvent(AggregateIdentifier orderbookIdentifier,
AggregateIdentifier portfolioIdentifier,
- long totalItems,
+ int totalItems,
long pricePerItem) {
this.orderbookIdentifier = orderbookIdentifier;
this.portfolioIdentifier = portfolioIdentifier;
@@ -53,7 +53,7 @@ public long getPricePerItem() {
return pricePerItem;
}
- public long getTotalItems() {
+ public int getTotalItems() {
return totalItems;
}
@@ -26,6 +26,6 @@ public BuyTransactionStartedEvent(AggregateIdentifier orderbookIdentifier,
AggregateIdentifier portfolioIdentifier,
long totalItems,
long pricePerItem) {
- super(orderbookIdentifier, portfolioIdentifier, totalItems, pricePerItem);
+ super(orderbookIdentifier, portfolioIdentifier, (int) totalItems, pricePerItem);
}
}
@@ -22,6 +22,6 @@
*/
public class SellTransactionStartedEvent extends AbstractTransactionStartedEvent {
public SellTransactionStartedEvent(AggregateIdentifier orderbookIdentifier, AggregateIdentifier portfolioIdentifier, long totalItems, long pricePerItem) {
- super(orderbookIdentifier, portfolioIdentifier, totalItems, pricePerItem);
+ super(orderbookIdentifier, portfolioIdentifier, (int) totalItems, pricePerItem);
}
}
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011. Gridshore
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.axonframework.samples.trader.app.command.trading;
+
+import org.axonframework.commandhandling.CommandBus;
+import org.axonframework.domain.AggregateIdentifier;
+import org.axonframework.saga.annotation.AbstractAnnotatedSaga;
+import org.axonframework.saga.annotation.SagaEventHandler;
+import org.axonframework.saga.annotation.StartSaga;
+import org.axonframework.samples.trader.app.api.portfolio.item.ConfirmItemReservationForPortfolioCommand;
+import org.axonframework.samples.trader.app.api.portfolio.item.ItemsReservedEvent;
+import org.axonframework.samples.trader.app.api.portfolio.item.NotEnoughItemsAvailableToReserveInPortfolio;
+import org.axonframework.samples.trader.app.api.portfolio.item.ReserveItemsCommand;
+import org.axonframework.samples.trader.app.api.transaction.SellTransactionStartedEvent;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author Jettro Coenradie
+ */
+public class SellTradeManagerSaga extends AbstractAnnotatedSaga {
+
+ private transient CommandBus commandBus;
+ private int totalItems;
+ private long pricePerItem;
+
+ @StartSaga
+ @SagaEventHandler(associationProperty = "transactionIdentifier")
+ public void handle(SellTransactionStartedEvent event) {
+ AggregateIdentifier orderbookIdentifier = event.getOrderbookIdentifier();
+ AggregateIdentifier portfolioIdentifier = event.getPortfolioIdentifier();
+
+ associateWith("orderbookIdentifier", orderbookIdentifier);
+ associateWith("portfolioIdentifier", portfolioIdentifier);
+
+ ReserveItemsCommand reserveItemsCommand =
+ new ReserveItemsCommand(portfolioIdentifier, orderbookIdentifier, event.getTotalItems());
+ pricePerItem = event.getPricePerItem();
+ totalItems = event.getTotalItems();
+ commandBus.dispatch(reserveItemsCommand);
+ }
+
+ @SagaEventHandler(associationProperty = "portfolioIdentifier")
+ public void handle(ItemsReservedEvent event) {
+ ConfirmItemReservationForPortfolioCommand command =
+ new ConfirmItemReservationForPortfolioCommand(event.getPortfolioIdentifier(), event.getItemIdentifier(), event.getAmountOfItemsReserved());
+ commandBus.dispatch(command);
+ }
+
+ @SagaEventHandler(associationProperty = "portfolioIdentifier")
+ public void handle(NotEnoughItemsAvailableToReserveInPortfolio event) {
+ // TODO jettro: not sure if I need to do something here, maybe inactivate this saga ?
+ }
+
+ /*-------------------------------------------------------------------------------------------*/
+ /* Getters and setters */
+ /*-------------------------------------------------------------------------------------------*/
+ @Autowired
+ public void setCommandBus(CommandBus commandBus) {
+ this.commandBus = commandBus;
+ }
+}
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2011. Gridshore
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.axonframework.samples.trader.app.command.trading;
-
-import org.axonframework.saga.annotation.AbstractAnnotatedSaga;
-
-/**
- * @author Jettro Coenradie
- */
-public class TradeManagerSaga extends AbstractAnnotatedSaga {
-
-}
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011. Gridshore
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.axonframework.samples.trader.app.command.trading;
+
+import org.axonframework.domain.AggregateIdentifier;
+import org.axonframework.domain.UUIDAggregateIdentifier;
+import org.axonframework.samples.trader.app.api.portfolio.item.ItemsReservedEvent;
+import org.axonframework.samples.trader.app.api.transaction.SellTransactionStartedEvent;
+import org.axonframework.samples.trader.app.command.trading.matchers.ReservedItemsCommandMatcher;
+import org.axonframework.test.saga.AnnotatedSagaTestFixture;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * @author Jettro Coenradie
+ */
+public class SellTradeManagerSagaTest {
+ AggregateIdentifier transaction = new UUIDAggregateIdentifier();
+ AggregateIdentifier orderbookIdentifier = new UUIDAggregateIdentifier();
+ AggregateIdentifier portfolioIdentifier = new UUIDAggregateIdentifier();
+ AggregateIdentifier itemIdentifier = new UUIDAggregateIdentifier();
+
+ @Before
+ public void setUp() throws Exception {
+
+ }
+
+ @Test
+ public void testHandle_SellTransactionStarted() throws Exception {
+ AnnotatedSagaTestFixture fixture = new AnnotatedSagaTestFixture(SellTradeManagerSaga.class);
+ fixture.givenAggregate(transaction).published()
+ .whenAggregate(transaction).publishes(new SellTransactionStartedEvent(orderbookIdentifier, portfolioIdentifier, 100, 10))
+ .expectAssociationWith("orderbookIdentifier", orderbookIdentifier)
+ .expectAssociationWith("portfolioIdentifier", portfolioIdentifier)
+ .expectActiveSagas(1)
+ .expectDispatchedCommandsMatching(new ReservedItemsCommandMatcher(orderbookIdentifier.asString(), portfolioIdentifier.asString(), 100));
+ }
+
+ @Test
+ @Ignore
+ public void testHandle_ItemsReserved() {
+ AnnotatedSagaTestFixture fixture = new AnnotatedSagaTestFixture(SellTradeManagerSaga.class);
+ fixture.givenAggregate(transaction).published(new SellTransactionStartedEvent(orderbookIdentifier, portfolioIdentifier, 100, 10))
+ .whenAggregate(transaction).publishes(new ItemsReservedEvent(itemIdentifier, 100))
+ .expectActiveSagas(1)
+ .expectDispatchedCommandsMatching(new ReservedItemsCommandMatcher(orderbookIdentifier.asString(), portfolioIdentifier.asString(), 100));
+ }
+
+}
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011. Gridshore
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.axonframework.samples.trader.app.command.trading.matchers;
+
+import org.axonframework.samples.trader.app.api.portfolio.item.ReserveItemsCommand;
+
+/**
+ * @author Jettro Coenradie
+ */
+public class ReservedItemsCommandMatcher extends TradeManagerSagaMatcher<ReserveItemsCommand> {
+ private String itemIdentifier;
+ private String portfolioIdentifier;
+ private int amountOfReservedItems;
+
+ public ReservedItemsCommandMatcher(String itemIdentifier, String portfolioIdentifier, int amountOfReservedItems) {
+ this.itemIdentifier = itemIdentifier;
+ this.portfolioIdentifier = portfolioIdentifier;
+ this.amountOfReservedItems = amountOfReservedItems;
+ }
+
+ @Override
+ public boolean doMatch(ReserveItemsCommand command) {
+ if (!command.getItemIdentifier().asString().equals(itemIdentifier)) {
+ problem = String.format("Item identifier is not as expected, required %s but received %s", itemIdentifier, command.getItemIdentifier());
+ return false;
+ }
+ if (!command.getPortfolioIdentifier().asString().equals(portfolioIdentifier)) {
+ problem = String.format("Portfolio identifier is not as expected, required %s but received %s", portfolioIdentifier, command.getPortfolioIdentifier());
+ return false;
+ }
+ if (amountOfReservedItems != command.getAmountOfItemsToReserve()) {
+ problem = String.format("Wrong amount of reserved items, required %d but received %d", amountOfReservedItems, command.getAmountOfItemsToReserve());
+ return false;
+ }
+ return true;
+ }
+}
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011. Gridshore
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.axonframework.samples.trader.app.command.trading.matchers;
+
+import org.axonframework.samples.trader.app.api.portfolio.item.ReserveItemsCommand;
+import org.hamcrest.Description;
+import org.mockito.ArgumentMatcher;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.List;
+
+/**
+ * @author Jettro Coenradie
+ */
+public abstract class TradeManagerSagaMatcher<T> extends ArgumentMatcher<T> {
+ protected String problem;
+
+ @Override
+ public boolean matches(Object argument) {
+ Object singleArgument;
+ if (argument instanceof List) {
+ singleArgument = ((List) argument).get(0);
+ } else {
+ singleArgument = argument;
+ }
+ ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
+ Class<?> clazz = (Class<?>) pt.getActualTypeArguments()[0];
+ if (!argument.getClass().equals(clazz)) {
+ problem = String.format("Wrong argument type, required %s but received %s", ReserveItemsCommand.class.getName(), argument.getClass().getName());
+ }
+ return doMatch((T) singleArgument);
+ }
+
+ public abstract boolean doMatch(T singleArgument);
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(problem);
+ }
+
+}
View
@@ -30,7 +30,7 @@
<spring.version>3.1.0.RC1</spring.version>
<spring.security.version>3.1.0.RC3</spring.security.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <axon.version>2.0-SNAPSHOT</axon.version>
+ <axon.version>1.3-SNAPSHOT</axon.version>
</properties>
<modules>
@@ -44,6 +44,7 @@ public String show(Model model) {
return "dashboard/index";
}
+ @SuppressWarnings("SpringJavaAutowiringInspection")
@Autowired
public void setPortfolioRepository(PortfolioQueryRepository portfolioRepository) {
this.portfolioRepository = portfolioRepository;
@@ -28,7 +28,6 @@
<mvc:annotation-driven validator="validator"/>
-
<mvc:view-controller path="/index.html" view-name="index"/>
<mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>

0 comments on commit 5974299

Please sign in to comment.