@Override public Tuple2<ConsumerEndpointFactoryBean, BarrierMessageHandler> doGet() { this.handler = new BarrierMessageHandler(this.timeout, this.outputProcessor, this.correlationStrategy); if (!this.adviceChain.isEmpty()) { this.handler.setAdviceChain(this.adviceChain); } this.handler.setRequiresReply(this.requiresReply); this.handler.setSendTimeout(this.sendTimeout); this.handler.setAsync(this.async); this.handler.setOrder(this.order); return super.doGet(); }
@Override public void trigger(Message<?> message) { Object key = this.correlationStrategy.getCorrelationKey(message); if (key == null) { throw new MessagingException(message, "Correlation Strategy returned null"); } SynchronousQueue<Message<?>> syncQueue = createOrObtainQueue(key); try { if (!syncQueue.offer(message, this.timeout, TimeUnit.MILLISECONDS)) { this.logger.error("Suspending thread timed out or did not arrive within timeout for: " + message); this.suspensions.remove(key); if (getDiscardChannel() != null) { this.messagingTemplate.send(getDiscardChannel(), message); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); this.logger.error("Interrupted while waiting for the suspending thread for: " + message); this.suspensions.remove(key); } }
private Object processRelease(Object key, Message<?> requestMessage, Message<?> releaseMessage) { this.suspensions.remove(key); if (releaseMessage.getPayload() instanceof Throwable) { throw new MessagingException(requestMessage, "Releasing flow returned a throwable", (Throwable) releaseMessage.getPayload()); } else { return buildResult(key, requestMessage, releaseMessage); } }
@Override protected Object handleRequestMessage(Message<?> requestMessage) { Object key = this.correlationStrategy.getCorrelationKey(requestMessage); if (key == null) { throw new MessagingException(requestMessage, "Correlation Strategy returned null"); } Thread existing = this.inProcess.putIfAbsent(key, Thread.currentThread()); if (existing != null) { throw new MessagingException(requestMessage, "Correlation key (" + key + ") is already in use by " + existing.getName()); } SynchronousQueue<Message<?>> syncQueue = createOrObtainQueue(key); try { Message<?> releaseMessage = syncQueue.poll(this.timeout, TimeUnit.MILLISECONDS); if (releaseMessage != null) { return processRelease(key, requestMessage, releaseMessage); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new MessageHandlingException(requestMessage, "Interrupted while waiting for release", e); } finally { this.inProcess.remove(key); this.suspensions.remove(key); } return null; }
@Test public void testRequiresReply() throws Exception { final BarrierMessageHandler handler = new BarrierMessageHandler(0); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); handler.setBeanFactory(mock(BeanFactory.class)); handler.setRequiresReply(true); handler.afterPropertiesSet(); try { handler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); fail("exception expected"); } catch (Exception e) { assertThat(e, Matchers.instanceOf(ReplyRequiredException.class)); } }
@Test public void testExceptionReply() throws Exception { final BarrierMessageHandler handler = new BarrierMessageHandler(10000); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); final AtomicReference<Exception> exception = new AtomicReference<Exception>(); final CountDownLatch latch = new CountDownLatch(1); exec.execute(() -> { try { handler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); handler.trigger(MessageBuilder.withPayload(exc).setCorrelationId("foo").build()); assertTrue(latch.await(10, TimeUnit.SECONDS)); assertSame(exc, exception.get().getCause());
@Test public void testLateReply() throws Exception { final BarrierMessageHandler handler = new BarrierMessageHandler(0); QueueChannel outputChannel = new QueueChannel(); QueueChannel discardChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); handler.setDiscardChannelName("discards"); handler.setChannelResolver(s -> discardChannel); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); final CountDownLatch latch = new CountDownLatch(1); ExecutorService exec = Executors.newSingleThreadExecutor(); exec.execute(() -> { handler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); latch.countDown(); }); new DirectFieldAccessor(handler).setPropertyValue("logger", logger); final Message<String> triggerMessage = MessageBuilder.withPayload("bar").setCorrelationId("foo").build(); handler.trigger(triggerMessage); ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); verify(logger).error(captor.capture()); Message<?> discard = discardChannel.receive(0); assertSame(discard, triggerMessage); handler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); assertEquals(0, suspensions.size()); exec.shutdownNow();
@ServiceActivator(inputChannel = "in") @Bean public BarrierMessageHandler barrier() { BarrierMessageHandler barrier = new BarrierMessageHandler(10000); barrier.setOutputChannel(out()); return barrier; }
@Test public void parserFieldPopulationTests() { BarrierMessageHandler handler = TestUtils.getPropertyValue(this.barrier1, "handler", BarrierMessageHandler.class); assertEquals(10000L, TestUtils.getPropertyValue(handler, "timeout")); assertTrue(TestUtils.getPropertyValue(handler, "requiresReply", Boolean.class)); assertThat(TestUtils.getPropertyValue(this.barrier2, "handler.correlationStrategy"), instanceOf(HeaderAttributeCorrelationStrategy.class)); assertThat(TestUtils.getPropertyValue(this.barrier3, "handler.messageGroupProcessor"), instanceOf(TestMGP.class)); assertThat(TestUtils.getPropertyValue(this.barrier3, "handler.correlationStrategy"), instanceOf(TestCS.class)); assertSame(handler.getDiscardChannel(), this.discards); }
/** * @since 5.0 */ @Override public MessageChannel getDiscardChannel() { if (this.discardChannel == null && this.discardChannelName != null && getChannelResolver() != null) { this.discardChannel = getChannelResolver().resolveDestination(this.discardChannelName); } return this.discardChannel; }
@Test public void testReplyBeforeRequest() throws Exception { final BarrierMessageHandler handler = new BarrierMessageHandler(10000); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); ExecutorService exec = Executors.newSingleThreadExecutor(); exec.execute(() -> handler.trigger(MessageBuilder.withPayload("bar").setCorrelationId("foo").build())); Map<?, ?> suspensions = TestUtils.getPropertyValue(handler, "suspensions", Map.class); int n = 0; while (n++ < 100 && suspensions.size() == 0) { Thread.sleep(100); } assertTrue("suspension did not appear in time", n < 100); handler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); Message<?> received = outputChannel.receive(10000); assertNotNull(received); List<?> result = (ArrayList<?>) received.getPayload(); assertEquals("foo", result.get(0)); assertEquals("bar", result.get(1)); assertEquals(0, suspensions.size()); exec.shutdownNow(); }
@Override protected Object handleRequestMessage(Message<?> requestMessage) { Object key = this.correlationStrategy.getCorrelationKey(requestMessage); if (key == null) { throw new MessagingException(requestMessage, "Correlation Strategy returned null"); } Thread existing = this.inProcess.putIfAbsent(key, Thread.currentThread()); if (existing != null) { throw new MessagingException(requestMessage, "Correlation key (" + key + ") is already in use by " + existing.getName()); } SynchronousQueue<Message<?>> syncQueue = createOrObtainQueue(key); try { Message<?> releaseMessage = syncQueue.poll(this.timeout, TimeUnit.MILLISECONDS); if (releaseMessage != null) { return processRelease(key, requestMessage, releaseMessage); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new MessageHandlingException(requestMessage, "Interrupted while waiting for release", e); } finally { this.inProcess.remove(key); this.suspensions.remove(key); } return null; }
/** * @since 5.0 */ @Override public MessageChannel getDiscardChannel() { if (this.discardChannel == null && this.discardChannelName != null && getChannelResolver() != null) { this.discardChannel = getChannelResolver().resolveDestination(this.discardChannelName); } return this.discardChannel; }
@Override public Tuple2<ConsumerEndpointFactoryBean, BarrierMessageHandler> doGet() { this.handler = new BarrierMessageHandler(this.timeout, this.outputProcessor, this.correlationStrategy); if (!this.adviceChain.isEmpty()) { this.handler.setAdviceChain(this.adviceChain); } this.handler.setRequiresReply(this.requiresReply); this.handler.setSendTimeout(this.sendTimeout); this.handler.setAsync(this.async); this.handler.setOrder(this.order); return super.doGet(); }
@Test public void testRequestBeforeReply() throws Exception { final BarrierMessageHandler handler = new BarrierMessageHandler(10000); QueueChannel outputChannel = new QueueChannel(); handler.setOutputChannel(outputChannel); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); final AtomicReference<Exception> dupCorrelation = new AtomicReference<Exception>(); final CountDownLatch latch = new CountDownLatch(1); Runnable runnable = () -> { try { handler.handleMessage(MessageBuilder.withPayload("foo").setCorrelationId("foo").build()); assertNotNull(dupCorrelation.get()); assertThat(dupCorrelation.get().getMessage(), startsWith("Correlation key (foo) is already in use by")); handler.trigger(MessageBuilder.withPayload("bar").setCorrelationId("foo").build()); Message<?> received = outputChannel.receive(10000); assertNotNull(received);
@Override public void trigger(Message<?> message) { Object key = this.correlationStrategy.getCorrelationKey(message); if (key == null) { throw new MessagingException(message, "Correlation Strategy returned null"); } SynchronousQueue<Message<?>> syncQueue = createOrObtainQueue(key); try { if (!syncQueue.offer(message, this.timeout, TimeUnit.MILLISECONDS)) { this.logger.error("Suspending thread timed out or did not arrive within timeout for: " + message); this.suspensions.remove(key); if (getDiscardChannel() != null) { this.messagingTemplate.send(getDiscardChannel(), message); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); this.logger.error("Interrupted while waiting for the suspending thread for: " + message); this.suspensions.remove(key); } }
private Object processRelease(Object key, Message<?> requestMessage, Message<?> releaseMessage) { this.suspensions.remove(key); if (releaseMessage.getPayload() instanceof Throwable) { throw new MessagingException(requestMessage, "Releasing flow returned a throwable", (Throwable) releaseMessage.getPayload()); } else { return buildResult(key, requestMessage, releaseMessage); } }
@Override public Tuple2<ConsumerEndpointFactoryBean, BarrierMessageHandler> doGet() { BarrierMessageHandler barrierMessageHandler = new BarrierMessageHandler(this.timeout, this.outputProcessor, this.correlationStrategy); barrierMessageHandler.setAdviceChain(this.adviceChain); barrierMessageHandler.setRequiresReply(this.requiresReply); barrierMessageHandler.setSendTimeout(this.sendTimeout); barrierMessageHandler.setAsync(this.async); barrierMessageHandler.setOrder(this.order); this.endpointFactoryBean.setHandler(barrierMessageHandler); return Tuples.of(this.endpointFactoryBean, barrierMessageHandler); }
@Override public Tuple2<ConsumerEndpointFactoryBean, BarrierMessageHandler> doGet() { BarrierMessageHandler barrierMessageHandler = new BarrierMessageHandler(this.timeout, this.outputProcessor, this.correlationStrategy); barrierMessageHandler.setAdviceChain(this.adviceChain); barrierMessageHandler.setRequiresReply(this.requiresReply); barrierMessageHandler.setSendTimeout(this.sendTimeout); barrierMessageHandler.setAsync(this.async); barrierMessageHandler.setOrder(this.order); this.endpointFactoryBean.setHandler(barrierMessageHandler); return Tuples.of(this.endpointFactoryBean, barrierMessageHandler); }