@Test public void testCreateOrder() throws InterruptedException { OrderId orderId = new OrderId(); commandGateway.send(new CreateOrderCommand(orderId, "TestOrder")); UnitOfWork unitOfWork = unitOfWorkProvider.get(); Assert.assertEquals( "Order is not created", orderRepository.load(orderId).getIdentifier(), orderId); unitOfWork.commit(); ItemId itemId1 = new ItemId(); commandGateway.send(new AddOrderItemCommand(orderId, itemId1, 10)); final AtomicBoolean injectionSuccessful = new AtomicBoolean(); commandGateway.send( new RemoveOrderItemCommand(orderId, itemId1), new CommandCallback<Boolean>() { @Override public void onSuccess(Boolean result) { injectionSuccessful.set(true); } @Override public void onFailure(Throwable cause) { logger.error("Error", cause); } }); Assert.assertTrue( "Injection into @CommandHandler method is not successful", injectionSuccessful.get()); }
private void offsetIfPossible(Date offsetDate) { if (offsetStatus == TransactionStatus.OFFSETED && accountPayableStatus == TransactionStatus.CONFIRMED && paidFeeStatus == TransactionStatus.CONFIRMED) { commandGateway.send( new OffsetAccountPayableFeeCommand(accountPayableId, offsetId, offsetDate)); commandGateway.send(new OffsetPaidFeeCommand(paidFeeId, offsetId, offsetDate)); } }
@SagaEventHandler(associationProperty = "offsetId") public void onOffsetCancelled(final OffsetCancelledEvent event) { offsetStatus = TransactionStatus.CANCELLED; commandGateway.send( new CancelAccountPayableFeeCommand( accountPayableId, com.icoin.trading.api.fee.domain.fee.CancelledReason.OFFSET_ERROR, event.getCancelledDate())); commandGateway.send( new CancelPaidFeeCommand( paidFeeId, com.icoin.trading.api.fee.domain.fee.CancelledReason.OFFSET_ERROR, event.getCancelledDate())); }
@SagaEventHandler(associationProperty = "feeId", keyName = "accountPayableId") public void onPayableCreated(final AccountPayableFeeCreatedEvent event) { accountPayableStatus = TransactionStatus.CREATED; commandGateway.send( new ConfirmAccountPayableFeeCommand(event.getFeeId(), event.getBusinessCreationTime())); }
/** * Tests that exceptions thrown by dispatch interceptors on another thread are handled properly. * * <p>Documentation states, * * <blockquote> * * Exceptions have the following effect:<br> * Any declared checked exception will be thrown if the Command Handler (or an interceptor) threw * an exceptions of that type. If a checked exception is thrown that has not been declared, it is * wrapped in a CommandExecutionException, which is a RuntimeException.<br> * … * * </blockquote> */ @Test( expected = SecurityException.class, // per documentation, an unchecked exception (theoretically // the only kind throwable by an interceptor) is returned unwrapped timeout = 10000) // bug is that the caller waits forever for a CommandCallback.onFailure that never // comes... public void testCommandDipatchInterceptorExceptionOnRetryThreadIsThrownToCaller() { commandGateway = new DefaultCommandGateway(commandBus, retryScheduler); // trigger retry commandBus.subscribe( String.class.getName(), new CommandHandler<String>() { @Override public Object handle(CommandMessage<String> commandMessage, UnitOfWork unitOfWork) throws Throwable { throw new ConcurrencyException("some retryable exception"); } }); // say we have a dispatch interceptor that expects to get the user's session from a // ThreadLocal... // yes, this should be configured on the gateway instead of the command bus, but still... final Thread testThread = Thread.currentThread(); commandBus.setDispatchInterceptors( Collections.singletonList( new CommandDispatchInterceptor() { @Override public CommandMessage<?> handle(CommandMessage<?> commandMessage) { if (Thread.currentThread() == testThread) { return commandMessage; // ok } else { // also, nothing is logged! LoggerFactory.getLogger(getClass()).info("throwing exception from dispatcher..."); throw new SecurityException("test dispatch interceptor exception"); } } })); // wait, but hopefully not forever... commandGateway.sendAndWait("command"); }
/** * It'd be nice if metadata added by a {@linkplain SimpleCommandBus#setDispatchInterceptors(List) * command bus's dispatch interceptors} could be preserved, too, but that doesn't seem to be * possible given how {@link RetryingCallback} works, so verify that it behaves as designed (if * not as "expected"). */ @Test(timeout = 10000) public void testCommandBusDispatchInterceptorMetaDataIsNotPreservedOnRetry() { final Thread testThread = Thread.currentThread(); commandGateway = new DefaultCommandGateway(commandBus, retryScheduler); // trigger retry, then return metadata for verification commandBus.subscribe( String.class.getName(), new CommandHandler<String>() { @Override public MetaData handle(CommandMessage<String> commandMessage, UnitOfWork unitOfWork) throws Throwable { if (Thread.currentThread() == testThread) { throw new ConcurrencyException("some retryable exception"); } else { return commandMessage.getMetaData(); } } }); commandBus.setDispatchInterceptors( Collections.singletonList( new CommandDispatchInterceptor() { @Override public CommandMessage<?> handle(CommandMessage<?> commandMessage) { if (Thread.currentThread() == testThread) { return commandMessage.andMetaData( Collections.singletonMap("commandBusMetaData", "myUserSession")); } else { // say the security interceptor example // from #testCommandDipatchInterceptorExceptionOnRetryThreadIsThrownToCaller // has been "fixed" -- on the retry thread, there's no security context return commandMessage.andMetaData( Collections.singletonMap("commandBusMetaData", "noUserSession")); } } })); assertEquals( "noUserSession", ((MetaData) commandGateway.sendAndWait("command")).get("commandBusMetaData")); }
/** * Tests that metadata added by a {@linkplain * AbstractCommandGateway#AbstractCommandGateway(CommandBus,RetryScheduler,List) command gateway's * dispatch interceptors} is preserved on retry. * * <p>It'd be nice if metadata added by a {@linkplain * SimpleCommandBus#setDispatchInterceptors(List) command bus's dispatch interceptors} could be * preserved, too, but that doesn't seem to be possible given how {@link RetryingCallback} works, * so verify that it is not preserved. */ @Test(timeout = 10000) public void testCommandGatewayDispatchInterceptorMetaDataIsPreservedOnRetry() { final Thread testThread = Thread.currentThread(); commandGateway = new DefaultCommandGateway( commandBus, retryScheduler, new CommandDispatchInterceptor() { @Override public CommandMessage<?> handle(CommandMessage<?> commandMessage) { if (Thread.currentThread() == testThread) { return commandMessage.andMetaData( Collections.singletonMap("gatewayMetaData", "myUserSession")); } else { // gateway interceptor should only be called from the caller's thread throw new SecurityException("test dispatch interceptor exception"); } } }); // trigger retry, then return metadata for verification commandBus.subscribe( String.class.getName(), new CommandHandler<String>() { @Override public MetaData handle(CommandMessage<String> commandMessage, UnitOfWork unitOfWork) throws Throwable { if (Thread.currentThread() == testThread) { throw new ConcurrencyException("some retryable exception"); } else { return commandMessage.getMetaData(); } } }); assertEquals( "myUserSession", ((MetaData) commandGateway.sendAndWait("command")).get("gatewayMetaData")); }
@SagaEventHandler(associationProperty = "todoId") public void onDeadlineExpired(ToDoItemDeadlineExpiredEvent event) { commandGateway.send(new MarkToDoItemOverdueCommand(event.getTodoId())); }
@Override public void approveClient(final String clientId, final Boolean approved, final String comment) { commandGateway.send(new ApproveClientCommand(clientId, approved, comment)); }
@Override public String createClient(final Client client) { commandGateway.send( new CreateClientCommand(client.getUniqueId(), client.getFirstName(), client.getLastName())); return client.getUniqueId(); }
@SagaEventHandler(associationProperty = "offsetId") public void onOffsetCreated(final OffsetCreatedEvent event) { offsetStatus = TransactionStatus.CONFIRMED; commandGateway.send(new OffsetFeesCommand(offsetId, event.getStartedDate())); }
@SagaEventHandler(associationProperty = "offsetId") public void onOffsetAmountNotMatched(final OffsetAmountNotMatchedEvent event) { commandGateway.send( new CancelOffsetCommand( offsetId, CancelledReason.AMOUNT_NOT_MATCHED, event.getOffsetDate())); }