@Override protected void handleMessageInternal(Message<?> message) throws Exception { Object correlationKey = this.correlationStrategy.getCorrelationKey(message); Object lock = getLock(correlationKey); synchronized (lock) { this.store.addMessagesToGroup(correlationKey, message); } if (log.isDebugEnabled()) { log.debug(String.format("Handled message for key [%s]: %s.", correlationKey, message)); } }
@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); } }
@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 bufferCompletesNormally() throws Exception { String correlationKey = "key"; Message<?> message1 = testMessage(correlationKey, 1, 2); Message<?> message2 = testMessage(correlationKey, 2, 2); when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn(correlationKey); when(processor.processMessageGroup(any(MessageGroup.class))).thenReturn(MessageBuilder.withPayload("grouped").build()); when(outputChannel.send(any(Message.class))).thenReturn(true); handler.handleMessage(message1); handler.handleMessage(message2); verify(correlationStrategy).getCorrelationKey(message1); verify(correlationStrategy).getCorrelationKey(message2); verify(processor).processMessageGroup(isA(SimpleMessageGroup.class)); }
@Override protected void handleMessageInternal(Message<?> message) throws InterruptedException { Object correlationKey = this.correlationStrategy.getCorrelationKey(message); Assert.state(correlationKey != null, "Null correlation not allowed. Maybe the CorrelationStrategy is failing?");
@Before public void initializeBarrier() { barrier = new CorrelatingMessageBarrier(); barrier.setCorrelationStrategy(correlationStrategy); barrier.setReleaseStrategy(releaseStrategy); when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn("foo"); when(releaseStrategy.canRelease(isA(MessageGroup.class))).thenReturn(true); }
@Test public void shouldNotPruneWhileCompleting() throws Exception { String correlationKey = "key"; final Message<?> message1 = testMessage(correlationKey, 1, 2); final Message<?> message2 = testMessage(correlationKey, 2, 2); final List<Message<?>> storedMessages = new ArrayList<Message<?>>(); final CountDownLatch bothMessagesHandled = new CountDownLatch(2); when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn(correlationKey); when(processor.processMessageGroup(any(MessageGroup.class))).thenReturn(MessageBuilder.withPayload("grouped").build()); when(outputChannel.send(any(Message.class))).thenReturn(true); handler.handleMessage(message1); bothMessagesHandled.countDown(); storedMessages.add(message1); ExecutorService exec = Executors.newSingleThreadExecutor(); exec.submit(() -> { handler.handleMessage(message2); storedMessages.add(message2); bothMessagesHandled.countDown(); }); assertTrue(bothMessagesHandled.await(10, TimeUnit.SECONDS)); assertEquals(0, store.expireMessageGroups(10000)); exec.shutdownNow(); }
@Test public void testNullCorrelationKey() throws Exception { final Message<?> message1 = MessageBuilder.withPayload("foo").build(); when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn(null); try { handler.handleMessage(message1); fail("Expected MessageHandlingException"); } catch (MessageHandlingException e) { Throwable cause = e.getCause(); boolean pass = cause instanceof IllegalStateException && cause.getMessage().toLowerCase().contains("null correlation"); if (!pass) { throw e; } } }
@Test public void shouldRemoveKeyWithoutLockingOnEmptyQueue() throws InterruptedException { Message<Object> message = testMessage(); Message<Object> message2 = testMessage(); barrier.handleMessage(message); verify(correlationStrategy).getCorrelationKey(message); assertThat(barrier.receive(), is(notNullValue())); barrier.handleMessage(message2); assertThat(barrier.receive(), is(notNullValue())); assertThat(barrier.receive(), is(nullValue())); }
@Test public void bufferCompletesWithException() throws Exception { doAnswer(new ThrowsException(new RuntimeException("Planned test exception"))) .when(processor).processMessageGroup(isA(SimpleMessageGroup.class)); String correlationKey = "key"; Message<?> message1 = testMessage(correlationKey, 1, 2); Message<?> message2 = testMessage(correlationKey, 2, 2); when(correlationStrategy.getCorrelationKey(isA(Message.class))).thenReturn(correlationKey); handler.setExpireGroupsUponCompletion(true); handler.handleMessage(message1); try { handler.handleMessage(message2); fail("Expected MessageHandlingException"); } catch (MessageHandlingException e) { assertEquals(0, store.getMessageGroup(correlationKey).size()); } verify(correlationStrategy).getCorrelationKey(message1); verify(correlationStrategy).getCorrelationKey(message2); verify(processor).processMessageGroup(isA(SimpleMessageGroup.class)); }
@Override protected void handleMessageInternal(Message<?> message) throws Exception { Object correlationKey = this.correlationStrategy.getCorrelationKey(message); Object lock = getLock(correlationKey); synchronized (lock) { this.store.addMessagesToGroup(correlationKey, message); } if (log.isDebugEnabled()) { log.debug(String.format("Handled message for key [%s]: %s.", correlationKey, message)); } }
@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); } }
@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; }
@Override protected final void handleMessageInternal(Message<?> message) { if (!this.initialized) { this.afterPropertiesSet(); } Object correlationKey = this.correlationStrategy.getCorrelationKey(message); if (correlationKey == null) { throw new MessageHandlingException(message, this.getClass().getSimpleName() + " requires the 'correlationKey' property"); } if (this.trackedCorrelationIds != null && this.trackedCorrelationIds.contains(correlationKey)) { if (logger.isDebugEnabled()) { logger.debug("Handling of Message group with correlationKey '" + correlationKey + "' has already completed or timed out."); } this.discardMessage(message); } else { this.processMessage(message, correlationKey); } }
@Override protected void handleMessageInternal(Message<?> message) throws Exception { Object correlationKey = this.correlationStrategy.getCorrelationKey(message); Assert.state(correlationKey != null, "Null correlation not allowed. Maybe the CorrelationStrategy is failing?");