/** * Create an ExecutorChannel with a {@link LoadBalancingStrategy} that * delegates to the provided {@link Executor} when dispatching Messages. * <p> * The Executor must not be null. * @param executor The executor. * @param loadBalancingStrategy The load balancing strategy implementation. */ public ExecutorChannel(Executor executor, LoadBalancingStrategy loadBalancingStrategy) { super(executor); Assert.notNull(executor, "executor must not be null"); UnicastingDispatcher unicastingDispatcher = new UnicastingDispatcher(executor); if (loadBalancingStrategy != null) { this.loadBalancingStrategy = loadBalancingStrategy; unicastingDispatcher.setLoadBalancingStrategy(loadBalancingStrategy); } this.dispatcher = unicastingDispatcher; }
@Override public final boolean dispatch(final Message<?> message) { if (this.executor != null) { Runnable task = createMessageHandlingTask(message); this.executor.execute(task); return true; } return this.doDispatch(message); }
private boolean doDispatch(Message<?> message) { if (tryOptimizedDispatch(message)) { return true; } boolean success = false; Iterator<MessageHandler> handlerIterator = this.getHandlerIterator(message); if (!handlerIterator.hasNext()) { throw new MessageDispatchingException(message, "Dispatcher has no subscribers"); } List<RuntimeException> exceptions = new ArrayList<RuntimeException>(); while (!success && handlerIterator.hasNext()) { MessageHandler handler = handlerIterator.next(); try { handler.handleMessage(message); success = true; // we have a winner. } catch (Exception e) { RuntimeException runtimeException = IntegrationUtils.wrapInDeliveryExceptionIfNecessary(message, () -> "Dispatcher failed to deliver Message", e); exceptions.add(runtimeException); this.handleExceptions(exceptions, message, !handlerIterator.hasNext()); } } return success; }
@Override public final void onInit() { Assert.state(getDispatcher().getHandlerCount() == 0, "You cannot subscribe() until the channel " + "bean is fully initialized by the framework. Do not subscribe in a @Bean definition"); super.onInit(); if (!(this.executor instanceof ErrorHandlingTaskExecutor)) { ErrorHandler errorHandler = new MessagePublishingErrorHandler( new BeanFactoryChannelResolver(this.getBeanFactory())); this.executor = new ErrorHandlingTaskExecutor(this.executor, errorHandler); } UnicastingDispatcher unicastingDispatcher = new UnicastingDispatcher(this.executor); unicastingDispatcher.setFailover(this.failover); if (this.maxSubscribers == null) { this.maxSubscribers = getIntegrationProperty(IntegrationProperties.CHANNELS_MAX_UNICAST_SUBSCRIBERS, Integer.class); } unicastingDispatcher.setMaxSubscribers(this.maxSubscribers); if (this.loadBalancingStrategy != null) { unicastingDispatcher.setLoadBalancingStrategy(this.loadBalancingStrategy); } unicastingDispatcher.setMessageHandlingTaskDecorator(task -> { if (ExecutorChannel.this.executorInterceptorsSize > 0) { return new MessageHandlingTask(task); } else { return task; } }); this.dispatcher = unicastingDispatcher; }
@Test public void noDuplicateSubscriptions() { UnicastingDispatcher dispatcher = new UnicastingDispatcher(); final AtomicInteger counter = new AtomicInteger(); MessageHandler target = new CountingTestEndpoint(counter, false); dispatcher.addHandler(target); dispatcher.addHandler(target); try { dispatcher.dispatch(new GenericMessage<>("test")); } catch (Exception e) { // ignore } assertEquals("target should not have duplicate subscriptions", 1, counter.get()); }
public void setBeanFactory(BeanFactory beanFactory) { if (!(this.taskExecutor instanceof ErrorHandlingTaskExecutor)) { ErrorHandler errorHandler = new MessagePublishingErrorHandler(new BeanFactoryChannelResolver(beanFactory)); this.taskExecutor = new ErrorHandlingTaskExecutor(this.taskExecutor, errorHandler); } this.dispatcher = new UnicastingDispatcher(this.taskExecutor); this.dispatcher.setFailover(this.failover); if (this.loadBalancingStrategy != null) { this.dispatcher.setLoadBalancingStrategy(this.loadBalancingStrategy); } }
@Test(expected = MessageDeliveryException.class) public void removeConsumerLastTargetCausesDeliveryException() { UnicastingDispatcher dispatcher = new UnicastingDispatcher(); final AtomicInteger counter = new AtomicInteger(); MessageHandler target = new CountingTestEndpoint(counter, false); dispatcher.addHandler(target); try { dispatcher.dispatch(new GenericMessage<>("test1")); } catch (Exception e) { // ignore } assertEquals(1, counter.get()); dispatcher.removeHandler(target); dispatcher.dispatch(new GenericMessage<>("test2")); }
/** * Create a DirectChannel with a {@link LoadBalancingStrategy}. The * strategy <em>must not</em> be null. * * @param loadBalancingStrategy The load balancing strategy implementation. */ public DirectChannel(LoadBalancingStrategy loadBalancingStrategy) { this.dispatcher.setLoadBalancingStrategy(loadBalancingStrategy); }
doThrow(new MessageRejectedException(message, null)).when(handlerA).handleMessage(message); UnicastingDispatcher dispatcher = channel.getDispatcher(); dispatcher.setLoadBalancingStrategy(new RoundRobinLoadBalancingStrategy()); dispatcher.addHandler(handlerA); dispatcher.addHandler(handlerB); dispatcher.addHandler(handlerC); InOrder inOrder = inOrder(handlerA, handlerB, handlerC); try {
/** * Specify whether the channel's dispatcher should have failover enabled. * By default, it will. Set this value to 'false' to disable it. * * @param failover The failover boolean. */ public void setFailover(boolean failover) { this.dispatcher.setFailover(failover); }
private boolean doDispatch(Message<?> message) { boolean success = false; Iterator<MessageHandler> handlerIterator = this.getHandlerIterator(message); if (!handlerIterator.hasNext()) { throw new MessageDeliveryException(message, "Dispatcher has no subscribers."); } List<RuntimeException> exceptions = new ArrayList<RuntimeException>(); while (success == false && handlerIterator.hasNext()) { MessageHandler handler = handlerIterator.next(); try { handler.handleMessage(message); success = true; // we have a winner. } catch (Exception e) { RuntimeException runtimeException = (e instanceof RuntimeException) ? (RuntimeException) e : new MessageDeliveryException(message, "Dispatcher failed to deliver Message.", e); exceptions.add(runtimeException); this.handleExceptions(exceptions, message, !handlerIterator.hasNext()); } } return success; }
/** * Returns the iterator that will be used to loop over the handlers. * Delegates to a {@link LoadBalancingStrategy} if available. Otherwise, * it simply returns the Iterator for the existing handler List. */ private Iterator<MessageHandler> getHandlerIterator(Message<?> message) { if (this.loadBalancingStrategy != null) { return this.loadBalancingStrategy.getHandlerIterator(message, this.getHandlers()); } return this.getHandlers().iterator(); }
public final boolean dispatch(final Message<?> message) { if (this.taskExecutor != null) { this.taskExecutor.execute(new Runnable() { public void run() { doDispatch(message); } }); return true; } return this.doDispatch(message); }
@Override public final void onInit() { Assert.state(getDispatcher().getHandlerCount() == 0, "You cannot subscribe() until the channel " + "bean is fully initialized by the framework. Do not subscribe in a @Bean definition"); super.onInit(); if (!(this.executor instanceof ErrorHandlingTaskExecutor)) { ErrorHandler errorHandler = new MessagePublishingErrorHandler( new BeanFactoryChannelResolver(this.getBeanFactory())); this.executor = new ErrorHandlingTaskExecutor(this.executor, errorHandler); } UnicastingDispatcher unicastingDispatcher = new UnicastingDispatcher(this.executor); unicastingDispatcher.setFailover(this.failover); if (this.maxSubscribers == null) { this.maxSubscribers = getIntegrationProperty(IntegrationProperties.CHANNELS_MAX_UNICAST_SUBSCRIBERS, Integer.class); } unicastingDispatcher.setMaxSubscribers(this.maxSubscribers); if (this.loadBalancingStrategy != null) { unicastingDispatcher.setLoadBalancingStrategy(this.loadBalancingStrategy); } unicastingDispatcher.setMessageHandlingTaskDecorator(task -> { if (ExecutorChannel.this.executorInterceptorsSize > 0) { return new MessageHandlingTask(task); } else { return task; } }); this.dispatcher = unicastingDispatcher; }
@Test public void firstHandlerReturnsTrue() { UnicastingDispatcher dispatcher = new UnicastingDispatcher(); final AtomicInteger counter = new AtomicInteger(); MessageHandler target1 = new CountingTestEndpoint(counter, true); MessageHandler target2 = new CountingTestEndpoint(counter, false); MessageHandler target3 = new CountingTestEndpoint(counter, false); dispatcher.addHandler(target1); dispatcher.addHandler(target2); dispatcher.addHandler(target3); assertTrue(dispatcher.dispatch(new GenericMessage<>("test"))); assertEquals("only the first target should have been invoked", 1, counter.get()); }
@Test public void removeConsumerBeforeSend() { UnicastingDispatcher dispatcher = new UnicastingDispatcher(); final AtomicInteger counter = new AtomicInteger(); MessageHandler target1 = new CountingTestEndpoint(counter, false); MessageHandler target2 = new CountingTestEndpoint(counter, false); MessageHandler target3 = new CountingTestEndpoint(counter, false); dispatcher.addHandler(target1); dispatcher.addHandler(target2); dispatcher.addHandler(target3); dispatcher.removeHandler(target2); try { dispatcher.dispatch(new GenericMessage<>("test")); } catch (Exception e) { // ignore } assertEquals(2, counter.get()); }
@Before public void setupDispatcher() { this.dispatcher.setLoadBalancingStrategy(new RoundRobinLoadBalancingStrategy()); }
/** * Specify whether the channel's dispatcher should have failover enabled. * By default, it will. Set this value to 'false' to disable it. * @param failover The failover boolean. */ public void setFailover(boolean failover) { this.failover = failover; getDispatcher().setFailover(failover); }
/** * Returns the iterator that will be used to loop over the handlers. * Delegates to a {@link LoadBalancingStrategy} if available. Otherwise, * it simply returns the Iterator for the existing handler List. */ private Iterator<MessageHandler> getHandlerIterator(Message<?> message) { if (this.loadBalancingStrategy != null) { return this.loadBalancingStrategy.getHandlerIterator(message, this.getHandlers()); } return this.getHandlers().iterator(); }
@Override protected AbstractDispatcher createDispatcher() { UnicastingDispatcher unicastingDispatcher = new UnicastingDispatcher(); unicastingDispatcher.setLoadBalancingStrategy(new RoundRobinLoadBalancingStrategy()); return unicastingDispatcher; }