@Bean public CommandBus commandBus() { SimpleCommandBus commandBus = new SimpleCommandBus(); commandBus.setHandlerInterceptors(Arrays.asList(new BeanValidationInterceptor())); // commandBus.setTransactionManager(new SpringTransactionManager(transactionManager)); return commandBus; }
/** * 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")); }
/** This test should make sure the problem described in issue #91 does not occur anymore */ @Test public void testCallbackCalled() { SimpleCommandBus scb = new SimpleCommandBus(); AnnotationCommandHandlerAdapter.subscribe(this, scb); scb.dispatch( GenericCommandMessage.asCommandMessage("Hello"), new VoidCallback() { @Override protected void onSuccess() { // what I expected } @Override public void onFailure(Throwable cause) { cause.printStackTrace(); fail("Did not expect a failure"); } }); }
/** * 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")); }