Permalink
Browse files

trying to start selling items through the mongo saga repository

  • Loading branch information...
1 parent cd94921 commit 7b60d52873c15ace1074f35acd5566a035ca15b4 @jettro jettro committed Jan 19, 2012
Showing with 3,095 additions and 12 deletions.
  1. +8 −1 README
  2. +3 −0 app/src/main/java/org/axonframework/samples/trader/app/api/company/CompanyCreatedEvent.java
  3. +3 −0 app/src/main/java/org/axonframework/samples/trader/app/api/company/CreateCompanyCommand.java
  4. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/AbstractOrderCommand.java
  5. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/AbstractOrderPlacedEvent.java
  6. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/BuyOrderPlacedEvent.java
  7. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/CreateBuyOrderCommand.java
  8. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/CreateOrderBookCommand.java
  9. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/CreateSellOrderCommand.java
  10. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/OrderBookCreatedEvent.java
  11. +2 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/SellOrderPlacedEvent.java
  12. +3 −0 app/src/main/java/org/axonframework/samples/trader/app/api/order/TradeExecutedEvent.java
  13. +20 −1 app/src/main/java/org/axonframework/samples/trader/app/command/trading/BuyTradeManagerSaga.java
  14. +19 −2 app/src/main/java/org/axonframework/samples/trader/app/command/trading/SellTradeManagerSaga.java
  15. +49 −0 app/src/main/java/org/axonframework/samples/trader/app/mongo/CFSagaMongoTemplate.java
  16. +9 −0 app/src/main/java/org/axonframework/samples/trader/app/query/portfolio/PortfolioEntry.java
  17. +9 −0 ...c/main/java/org/axonframework/samples/trader/app/query/portfolio/PortfolioMoneyEventListener.java
  18. +2 −0 ...c/main/java/org/axonframework/samples/trader/app/query/user/repositories/UserQueryRepository.java
  19. +13 −0 app/src/main/resources/META-INF/spring/cqrs-infrastructure-context.xml
  20. +4 −0 app/src/main/resources/META-INF/spring/persistence-infrastructure-context.xml
  21. +103 −0 web-ui/src/main/java/org/axonframework/samples/trader/webui/admin/AdminController.java
  22. +10 −5 web-ui/src/main/java/org/axonframework/samples/trader/webui/companies/CompanyController.java
  23. +8 −0 web-ui/src/main/java/org/axonframework/samples/trader/webui/security/UserController.java
  24. +2 −1 web-ui/src/main/resources/log4j.properties
  25. +2 −2 web-ui/src/main/webapp/WEB-INF/decorators/master.jsp
  26. +76 −0 web-ui/src/main/webapp/WEB-INF/jsp/admin/portfolio/detail.jsp
  27. +58 −0 web-ui/src/main/webapp/WEB-INF/jsp/admin/portfolio/list.jsp
  28. +33 −0 web-ui/src/main/webapp/WEB-INF/jsp/user/detail.jsp
  29. +2,645 −0 web-ui/src/main/webapp/style/bootstrap-1.4.0.min.css
View
9 README
@@ -28,4 +28,11 @@ Running the sample
Advanced configuration
----------------------
-To write when done :-)
+To write when done :-)
+
+
+Note to myself
+----------------------
+Should the ID of the transaction be the same are the ID of the order? Is that possible? There should most probably
+be a relation between the two. Think about this, since that would cross aggregate boundaries, which is not allowed.
+Think more about the domain concepts around this.
@@ -19,6 +19,9 @@
import org.axonframework.domain.DomainEvent;
/**
+ * <p>A new company is created with a certain value and an amount of shares. Those two values can be used to calculate
+ * the starting point for the value of a share.</p>
+ *
* @author Jettro Coenradie
*/
public class CompanyCreatedEvent extends DomainEvent {
@@ -18,6 +18,9 @@
import org.axonframework.domain.AggregateIdentifier;
/**
+ * <p>Create a new company by proving the name, the estiamted value of the company and the amount of shares that are
+ * available for the company. You also must provide the id of the user that wants to create the company.</p>
+ *
* @author Jettro Coenradie
*/
public class CreateCompanyCommand {
@@ -19,6 +19,8 @@
import org.axonframework.domain.UUIDAggregateIdentifier;
/**
+ * <p>Abstract parent class for all commands that are order related.</p>
+ *
* @author Allard Buijze
*/
public abstract class AbstractOrderCommand {
@@ -19,6 +19,8 @@
import org.axonframework.domain.DomainEvent;
/**
+ * <p>Abstract parent class for all buy and sell order placed events.</p>
+ *
* @author Allard Buijze
*/
public abstract class AbstractOrderPlacedEvent extends DomainEvent {
@@ -18,6 +18,8 @@
import org.axonframework.domain.AggregateIdentifier;
/**
+ * <p>A new Buy Order is placed.</p>
+ *
* @author Allard Buijze
*/
public class BuyOrderPlacedEvent extends AbstractOrderPlacedEvent {
@@ -18,6 +18,8 @@
import org.axonframework.domain.AggregateIdentifier;
/**
+ * <p>Create a new Buy Order.</p>
+ *
* @author Allard Buijze
*/
public class CreateBuyOrderCommand extends AbstractOrderCommand {
@@ -18,6 +18,8 @@
import org.axonframework.domain.AggregateIdentifier;
/**
+ * <p>Create a new OrderBook for the Company represented by the provided companyIdentifier.</p>
+ *
* @author Jettro Coenradie
*/
public class CreateOrderBookCommand {
@@ -18,6 +18,8 @@
import org.axonframework.domain.AggregateIdentifier;
/**
+ * <p>Create a new Sell Order using the amount of items to sell for the provided price.</p>
+ *
* @author Allard Buijze
*/
public class CreateSellOrderCommand extends AbstractOrderCommand {
@@ -19,6 +19,8 @@
import org.axonframework.domain.DomainEvent;
/**
+ * <p>A new OrderBook is created for the company with the provided identifier.</p>
+ *
* @author Jettro Coenradie
*/
public class OrderBookCreatedEvent extends DomainEvent {
@@ -18,6 +18,8 @@
import org.axonframework.domain.AggregateIdentifier;
/**
+ * <p>A new Sell Order is placed for the current OrderBook. </p>
+ *
* @author Allard Buijze
*/
public class SellOrderPlacedEvent extends AbstractOrderPlacedEvent {
@@ -19,6 +19,9 @@
import org.axonframework.domain.DomainEvent;
/**
+ * <p>A new trade has been executed. The event contains the amount of items that are traded and the price for the items
+ * that are traded. The event also contains the identifiers for the Buy Order and the Sell order.</p>
+ *
* @author Allard Buijze
*/
public class TradeExecutedEvent extends DomainEvent {
@@ -34,6 +34,12 @@
@StartSaga
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(BuyTransactionStartedEvent event) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("A new buy transaction is started with identifier {}, for portfolio with identifier {} and orderbook with identifier {}",
+ new Object[]{event.getTransactionIdentifier(), event.getPortfolioIdentifier(), event.getOrderbookIdentifier()});
+ logger.debug("The new buy transaction with identifier {} is for buying {} items for the price of {}",
+ new Object[]{event.getTransactionIdentifier(), event.getTotalItems(), event.getPricePerItem()});
+ }
setTransactionIdentifier(event.getTransactionIdentifier());
setOrderbookIdentifier(event.getOrderbookIdentifier());
setPortfolioIdentifier(event.getPortfolioIdentifier());
@@ -48,27 +54,36 @@ public void handle(BuyTransactionStartedEvent event) {
getCommandBus().dispatch(command);
}
+ /**
+ * TODO jettro: Moet er hier niet nog iets specifieks inkomen voor deze specifieke transactie? Anders kun je toch niet meerdere transacties per portfolio tegelijk uitvoeren?
+ *
+ * @param event
+ */
@SagaEventHandler(associationProperty = "portfolioIdentifier")
public void handle(MoneyReservedFromPortfolioEvent event) {
+ logger.debug("Money for transaction with identifier {} is reserved", getTransactionIdentifier());
ConfirmTransactionCommand command = new ConfirmTransactionCommand(getTransactionIdentifier());
getCommandBus().dispatch(command);
}
@SagaEventHandler(associationProperty = "portfolioIdentifier")
@EndSaga
public void handle(NotEnoughMoneyInPortfolioToMakeReservationEvent event) {
- // Nothing to do, no reservations were made and the transaction is finished
+ logger.debug("Not enough money was available to make reservation in transaction {} for portfolio {}. Required: {}",
+ new Object[]{getTransactionIdentifier(), event.getPortfolioIdentifier(), event.getAmountToPayInCents()});
}
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(BuyTransactionConfirmedEvent event) {
+ logger.debug("Buy Transaction {} is approved to make the buy order", event.getTransactionIdentifier());
CreateBuyOrderCommand command = new CreateBuyOrderCommand(getPortfolioIdentifier(), getOrderbookIdentifier(), getTotalItems(), getPricePerItem());
getCommandBus().dispatch(command);
}
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(BuyTransactionCancelledEvent event) {
long amountToCancel = (event.getTotalAmountOfItems() - event.getAmountOfExecutedItems()) * getPricePerItem();
+ logger.debug("Buy Transaction {} is cancelled, amount of money reserved to cancel is {}", event.getTransactionIdentifier(), amountToCancel);
CancelMoneyReservationFromPortfolioCommand command = new CancelMoneyReservationFromPortfolioCommand(getPortfolioIdentifier(), amountToCancel);
getCommandBus().dispatch(command);
}
@@ -77,6 +92,8 @@ public void handle(BuyTransactionCancelledEvent event) {
@SagaEventHandler(associationProperty = "transactionIdentifier")
@EndSaga
public void handle(BuyTransactionExecutedEvent event) {
+ logger.debug("Buy Transaction {} is executed, last amount of executed items is {} for a price of {}",
+ new Object[]{event.getTransactionIdentifier(), event.getAmountOfItems(), event.getItemPrice()});
ConfirmMoneyReservationFromPortfolionCommand confirmCommand =
new ConfirmMoneyReservationFromPortfolionCommand(getPortfolioIdentifier(), event.getAmountOfItems() * event.getItemPrice());
getCommandBus().dispatch(confirmCommand);
@@ -87,6 +104,8 @@ public void handle(BuyTransactionExecutedEvent event) {
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(BuyTransactionPartiallyExecutedEvent event) {
+ logger.debug("Buy Transaction {} is partially executed, amount of executed items is {} for a price of {}",
+ new Object[]{event.getTransactionIdentifier(), event.getAmountOfExecutedItems(), event.getItemPrice()});
ConfirmMoneyReservationFromPortfolionCommand confirmCommand =
new ConfirmMoneyReservationFromPortfolionCommand(getPortfolioIdentifier(), event.getAmountOfExecutedItems() * event.getItemPrice());
getCommandBus().dispatch(confirmCommand);
@@ -34,6 +34,13 @@
@StartSaga
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(SellTransactionStartedEvent event) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("A new sell transaction is started with identifier {}, for portfolio with identifier {} and orderbook with identifier {}",
+ new Object[]{event.getTransactionIdentifier(), event.getPortfolioIdentifier(), event.getOrderbookIdentifier()});
+ logger.debug("The sell transaction with identifier {} is for selling {} items for the price of {}",
+ new Object[]{event.getTransactionIdentifier(), event.getTotalItems(), event.getPricePerItem()});
+ }
+
setTransactionIdentifier(event.getTransactionIdentifier());
setOrderbookIdentifier(event.getOrderbookIdentifier());
setPortfolioIdentifier(event.getPortfolioIdentifier());
@@ -50,6 +57,7 @@ public void handle(SellTransactionStartedEvent event) {
@SagaEventHandler(associationProperty = "portfolioIdentifier")
public void handle(ItemsReservedEvent event) {
+ logger.debug("Items for transaction {} are reserved", getTransactionIdentifier());
ConfirmTransactionCommand confirmTransactionCommand = new ConfirmTransactionCommand(getTransactionIdentifier());
getCommandBus().dispatch(confirmTransactionCommand);
}
@@ -62,22 +70,28 @@ public void handle(NotEnoughItemsAvailableToReserveInPortfolio event) {
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(SellTransactionConfirmedEvent event) {
+ logger.debug("Sell Transaction {} is approved to make the buy order", event.getTransactionIdentifier());
+
CreateSellOrderCommand command = new CreateSellOrderCommand(getPortfolioIdentifier(), getOrderbookIdentifier(), getTotalItems(), getPricePerItem());
getCommandBus().dispatch(command);
}
@SagaEventHandler(associationProperty = "transactionIdentifier")
@EndSaga
public void handle(SellTransactionCancelledEvent event) {
- logger.debug("Saga for Sell Transaction with id {} is cancelled", event.getTransactionIdentifier());
+ long amountOfCancelledItems = event.getTotalAmountOfItems() - event.getAmountOfExecutedItems();
+ logger.debug("Sell Transaction {} is cancelled, amount of money reserved to cancel is {}", event.getTransactionIdentifier(), amountOfCancelledItems);
CancelItemReservationForPortfolioCommand command =
- new CancelItemReservationForPortfolioCommand(getPortfolioIdentifier(), getOrderbookIdentifier(), event.getTotalAmountOfItems() - event.getAmountOfExecutedItems());
+ new CancelItemReservationForPortfolioCommand(getPortfolioIdentifier(), getOrderbookIdentifier(), amountOfCancelledItems);
getCommandBus().dispatch(command);
}
@SagaEventHandler(associationProperty = "transactionIdentifier")
@EndSaga
public void handle(SellTransactionExecutedEvent event) {
+ logger.debug("Sell Transaction {} is executed, last amount of executed items is {} for a price of {}",
+ new Object[]{event.getTransactionIdentifier(), event.getAmountOfItems(), event.getItemPrice()});
+
ConfirmItemReservationForPortfolioCommand confirmCommand =
new ConfirmItemReservationForPortfolioCommand(getPortfolioIdentifier(), getOrderbookIdentifier(), event.getAmountOfItems());
getCommandBus().dispatch(confirmCommand);
@@ -88,6 +102,9 @@ public void handle(SellTransactionExecutedEvent event) {
@SagaEventHandler(associationProperty = "transactionIdentifier")
public void handle(SellTransactionPartiallyExecutedEvent event) {
+ logger.debug("Sell Transaction {} is partially executed, amount of executed items is {} for a price of {}",
+ new Object[]{event.getTransactionIdentifier(), event.getAmountOfExecutedItems(), event.getItemPrice()});
+
ConfirmItemReservationForPortfolioCommand confirmCommand =
new ConfirmItemReservationForPortfolioCommand(getPortfolioIdentifier(), getOrderbookIdentifier(), event.getAmountOfExecutedItems());
getCommandBus().dispatch(confirmCommand);
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012. 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.mongo;
+
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import org.axonframework.saga.repository.mongo.MongoTemplate;
+import org.springframework.data.mongodb.MongoDbFactory;
+
+/**
+ * @author Jettro Coenradie
+ */
+public class CFSagaMongoTemplate implements MongoTemplate {
+ static final String SAGA_ASSOCIATIONS = "sagaassociations";
+ static final String SAGA_COLLECTION = "sagacollection";
+ private MongoDbFactory mongoDbFactory;
+
+ public CFSagaMongoTemplate(MongoDbFactory mongoDbFactory) {
+ this.mongoDbFactory = mongoDbFactory;
+ }
+
+ @Override
+ public DBCollection sagaCollection() {
+ return database().getCollection(SAGA_COLLECTION);
+ }
+
+ @Override
+ public DBCollection associationsCollection() {
+ return database().getCollection(SAGA_ASSOCIATIONS);
+ }
+
+ @Override
+ public DB database() {
+ return mongoDbFactory.getDb();
+ }
+}
@@ -27,6 +27,7 @@
@Id
private String identifier;
private String userIdentifier;
+ private String userName;
private long amountOfMoney;
private long reservedAmountOfMoney;
@@ -111,6 +112,14 @@ public void setItemsReserved(Map<String, ItemEntry> itemsReserved) {
this.itemsReserved = itemsReserved;
}
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
/*-------------------------------------------------------------------------------------------*/
/* Private helper methods */
/*-------------------------------------------------------------------------------------------*/
@@ -19,6 +19,7 @@
import org.axonframework.samples.trader.app.api.portfolio.PortfolioCreatedEvent;
import org.axonframework.samples.trader.app.api.portfolio.money.*;
import org.axonframework.samples.trader.app.query.portfolio.repositories.PortfolioQueryRepository;
+import org.axonframework.samples.trader.app.query.user.repositories.UserQueryRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,6 +33,7 @@
private final static Logger logger = LoggerFactory.getLogger(PortfolioMoneyEventListener.class);
private PortfolioQueryRepository portfolioRepository;
+ private UserQueryRepository userQueryRepository;
@EventHandler
public void handleEvent(PortfolioCreatedEvent event) {
@@ -41,6 +43,7 @@ public void handleEvent(PortfolioCreatedEvent event) {
PortfolioEntry portfolioEntry = new PortfolioEntry();
portfolioEntry.setIdentifier(event.getPortfolioIdentifier().asString());
portfolioEntry.setUserIdentifier(event.getUserIdentifier().asString());
+ portfolioEntry.setUserName(userQueryRepository.findByIdentifier(event.getUserIdentifier().asString()).getFullName());
portfolioEntry.setAmountOfMoney(0);
portfolioEntry.setReservedAmountOfMoney(0);
@@ -95,4 +98,10 @@ public void handleEvent(MoneyReservationConfirmedFromPortfolioEvent event) {
public void setPortfolioRepository(PortfolioQueryRepository portfolioRepository) {
this.portfolioRepository = portfolioRepository;
}
+
+ @SuppressWarnings("SpringJavaAutowiringInspection")
+ @Autowired
+ public void setUserQueryRepository(UserQueryRepository userQueryRepository) {
+ this.userQueryRepository = userQueryRepository;
+ }
}
@@ -23,4 +23,6 @@
*/
public interface UserQueryRepository extends PagingAndSortingRepository<UserEntry, String> {
UserEntry findByUsername(String username);
+
+ UserEntry findByIdentifier(String identifier);
}
@@ -29,4 +29,17 @@
<bean id="eventStore" class="org.axonframework.eventstore.mongo.MongoEventStore">
<constructor-arg ref="mongoTemplate"/>
</bean>
+
+ <bean id="sagaRepository" class="org.axonframework.saga.repository.mongo.MongoSagaRepository">
+ <constructor-arg ref="mongoSagaTemplate"/>
+ </bean>
+
+ <axon:saga-manager id="sagaManager" saga-repository="sagaRepository" event-bus="eventBus">
+ <axon:types>
+ org.axonframework.samples.trader.app.command.trading.SellTradeManagerSaga,
+ org.axonframework.samples.trader.app.command.trading.BuyTradeManagerSaga
+ </axon:types>
+ </axon:saga-manager>
+
+ <bean id="resourceInjector" class="org.axonframework.saga.spring.SpringResourceInjector"/>
</beans>
@@ -34,6 +34,10 @@
<constructor-arg ref="mongoDbFactory"/>
</bean>
+ <bean id="mongoSagaTemplate" class="org.axonframework.samples.trader.app.mongo.CFSagaMongoTemplate">
+ <constructor-arg ref="mongoDbFactory"/>
+ </bean>
+
<beans profile="default">
<mongo:db-factory id="mongoDbFactory" dbname="axontrader" host="127.0.0.1" port="27017"/>
</beans>
Oops, something went wrong.

0 comments on commit 7b60d52

Please sign in to comment.