/* * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.jms.listener.adapter; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.Topic; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.support.StaticListableBeanFactory; import org.springframework.jms.StubTextMessage; import org.springframework.jms.support.JmsHeaders; import org.springframework.jms.support.converter.MappingJackson2MessageConverter; import org.springframework.jms.support.converter.MessageConverter; import org.springframework.jms.support.converter.MessageType; import org.springframework.messaging.Message; import org.springframework.messaging.converter.MessageConversionException; import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory; import org.springframework.messaging.support.MessageBuilder; import org.springframework.util.ReflectionUtils; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; /** * @author Stephane Nicoll */ public class MessagingMessageListenerAdapterTests { private final DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); private final SampleBean sample = new SampleBean(); @Before public void setup() { initializeFactory(factory); } @Test public void buildMessageWithStandardMessage() throws JMSException { Destination replyTo = new Destination() {}; Message result = MessageBuilder.withPayload("Response") .setHeader("foo", "bar") .setHeader(JmsHeaders.TYPE, "msg_type") .setHeader(JmsHeaders.REPLY_TO, replyTo) .build(); Session session = mock(Session.class); given(session.createTextMessage("Response")).willReturn(new StubTextMessage("Response")); MessagingMessageListenerAdapter listener = getSimpleInstance("echo", Message.class); javax.jms.Message replyMessage = listener.buildMessage(session, result); verify(session).createTextMessage("Response"); assertNotNull("reply should never be null", replyMessage); assertEquals("Response", ((TextMessage) replyMessage).getText()); assertEquals("custom header not copied", "bar", replyMessage.getStringProperty("foo")); assertEquals("type header not copied", "msg_type", replyMessage.getJMSType()); assertEquals("replyTo header not copied", replyTo, replyMessage.getJMSReplyTo()); } @Test public void exceptionInListener() { javax.jms.Message message = new StubTextMessage("foo"); Session session = mock(Session.class); MessagingMessageListenerAdapter listener = getSimpleInstance("fail", String.class); try { listener.onMessage(message, session); fail("Should have thrown an exception"); } catch (JMSException ex) { fail("Should not have thrown a JMS exception"); } catch (ListenerExecutionFailedException ex) { assertEquals(IllegalArgumentException.class, ex.getCause().getClass()); assertEquals("Expected test exception", ex.getCause().getMessage()); } } @Test public void exceptionInInvocation() { javax.jms.Message message = new StubTextMessage("foo"); Session session = mock(Session.class); MessagingMessageListenerAdapter listener = getSimpleInstance("wrongParam", Integer.class); try { listener.onMessage(message, session); fail("Should have thrown an exception"); } catch (JMSException ex) { fail("Should not have thrown a JMS exception"); } catch (ListenerExecutionFailedException ex) { assertEquals(MessageConversionException.class, ex.getCause().getClass()); } } @Test public void incomingMessageUsesMessageConverter() throws JMSException { javax.jms.Message jmsMessage = mock(javax.jms.Message.class); Session session = mock(Session.class); MessageConverter messageConverter = mock(MessageConverter.class); given(messageConverter.fromMessage(jmsMessage)).willReturn("FooBar"); MessagingMessageListenerAdapter listener = getSimpleInstance("simple", Message.class); listener.setMessageConverter(messageConverter); listener.onMessage(jmsMessage, session); verify(messageConverter, times(1)).fromMessage(jmsMessage); assertEquals(1, sample.simples.size()); assertEquals("FooBar", sample.simples.get(0).getPayload()); } @Test public void replyUsesMessageConverterForPayload() throws JMSException { Session session = mock(Session.class); MessageConverter messageConverter = mock(MessageConverter.class); given(messageConverter.toMessage("Response", session)).willReturn(new StubTextMessage("Response")); Message result = MessageBuilder.withPayload("Response").build(); MessagingMessageListenerAdapter listener = getSimpleInstance("echo", Message.class); listener.setMessageConverter(messageConverter); javax.jms.Message replyMessage = listener.buildMessage(session, result); verify(messageConverter, times(1)).toMessage("Response", session); assertNotNull("reply should never be null", replyMessage); assertEquals("Response", ((TextMessage) replyMessage).getText()); } @Test public void replyPayloadToQueue() throws JMSException { Message request = MessageBuilder.withPayload("Response").build(); Session session = mock(Session.class); Queue replyDestination = mock(Queue.class); given(session.createQueue("queueOut")).willReturn(replyDestination); MessageProducer messageProducer = mock(MessageProducer.class); TextMessage responseMessage = mock(TextMessage.class); given(session.createTextMessage("Response")).willReturn(responseMessage); given(session.createProducer(replyDestination)).willReturn(messageProducer); MessagingMessageListenerAdapter listener = getPayloadInstance(request, "replyPayloadToQueue", Message.class); listener.onMessage(mock(javax.jms.Message.class), session); verify(session).createQueue("queueOut"); verify(session).createTextMessage("Response"); verify(messageProducer).send(responseMessage); verify(messageProducer).close(); } @Test public void replyPayloadToTopic() throws JMSException { Message request = MessageBuilder.withPayload("Response").build(); Session session = mock(Session.class); Topic replyDestination = mock(Topic.class); given(session.createTopic("topicOut")).willReturn(replyDestination); MessageProducer messageProducer = mock(MessageProducer.class); TextMessage responseMessage = mock(TextMessage.class); given(session.createTextMessage("Response")).willReturn(responseMessage); given(session.createProducer(replyDestination)).willReturn(messageProducer); MessagingMessageListenerAdapter listener = getPayloadInstance(request, "replyPayloadToTopic", Message.class); listener.onMessage(mock(javax.jms.Message.class), session); verify(session).createTopic("topicOut"); verify(session).createTextMessage("Response"); verify(messageProducer).send(responseMessage); verify(messageProducer).close(); } @Test public void replyPayloadToDestination() throws JMSException { Queue replyDestination = mock(Queue.class); Message request = MessageBuilder.withPayload("Response") .setHeader("destination", replyDestination).build(); Session session = mock(Session.class); MessageProducer messageProducer = mock(MessageProducer.class); TextMessage responseMessage = mock(TextMessage.class); given(session.createTextMessage("Response")).willReturn(responseMessage); given(session.createProducer(replyDestination)).willReturn(messageProducer); MessagingMessageListenerAdapter listener = getPayloadInstance(request, "replyPayloadToDestination", Message.class); listener.onMessage(mock(javax.jms.Message.class), session); verify(session, times(0)).createQueue(anyString()); verify(session).createTextMessage("Response"); verify(messageProducer).send(responseMessage); verify(messageProducer).close(); } @Test public void replyPayloadNoDestination() throws JMSException { Queue replyDestination = mock(Queue.class); Message request = MessageBuilder.withPayload("Response").build(); Session session = mock(Session.class); MessageProducer messageProducer = mock(MessageProducer.class); TextMessage responseMessage = mock(TextMessage.class); given(session.createTextMessage("Response")).willReturn(responseMessage); given(session.createProducer(replyDestination)).willReturn(messageProducer); MessagingMessageListenerAdapter listener = getPayloadInstance(request, "replyPayloadNoDestination", Message.class); listener.setDefaultResponseDestination(replyDestination); listener.onMessage(mock(javax.jms.Message.class), session); verify(session, times(0)).createQueue(anyString()); verify(session).createTextMessage("Response"); verify(messageProducer).send(responseMessage); verify(messageProducer).close(); } @Test public void replyJackson() throws JMSException { TextMessage reply = testReplyWithJackson("replyJackson", "{\"counter\":42,\"name\":\"Response\",\"description\":\"lengthy description\"}"); verify(reply).setObjectProperty("foo", "bar"); } private TextMessage testReplyWithJackson(String methodName, String replyContent) throws JMSException { Queue replyDestination = mock(Queue.class); Message request = MessageBuilder.withPayload("Response").build(); Session session = mock(Session.class); MessageProducer messageProducer = mock(MessageProducer.class); TextMessage responseMessage = mock(TextMessage.class); given(session.createTextMessage(replyContent)).willReturn(responseMessage); given(session.createProducer(replyDestination)).willReturn(messageProducer); MessagingMessageListenerAdapter listener = getPayloadInstance(request, methodName, Message.class); MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter(); messageConverter.setTargetType(MessageType.TEXT); listener.setMessageConverter(messageConverter); listener.setDefaultResponseDestination(replyDestination); listener.onMessage(mock(javax.jms.Message.class), session); verify(session, times(0)).createQueue(anyString()); verify(session).createTextMessage(replyContent); verify(messageProducer).send(responseMessage); verify(messageProducer).close(); return responseMessage; } protected MessagingMessageListenerAdapter getSimpleInstance(String methodName, Class... parameterTypes) { Method m = ReflectionUtils.findMethod(SampleBean.class, methodName, parameterTypes); return createInstance(m); } protected MessagingMessageListenerAdapter createInstance(Method m) { MessagingMessageListenerAdapter adapter = new MessagingMessageListenerAdapter(); adapter.setHandlerMethod(factory.createInvocableHandlerMethod(sample, m)); return adapter; } protected MessagingMessageListenerAdapter getPayloadInstance(final Object payload, String methodName, Class... parameterTypes) { Method method = ReflectionUtils.findMethod(SampleBean.class, methodName, parameterTypes); MessagingMessageListenerAdapter adapter = new MessagingMessageListenerAdapter() { @Override protected Object extractMessage(javax.jms.Message message) { return payload; } }; adapter.setHandlerMethod(factory.createInvocableHandlerMethod(sample, method)); return adapter; } private void initializeFactory(DefaultMessageHandlerMethodFactory factory) { factory.setBeanFactory(new StaticListableBeanFactory()); factory.afterPropertiesSet(); } @SuppressWarnings("unused") private static class SampleBean { public final List> simples = new ArrayList<>(); public void simple(Message input) { simples.add(input); } public Message echo(Message input) { return MessageBuilder.withPayload(input.getPayload()) .setHeader(JmsHeaders.TYPE, "reply") .build(); } public JmsResponse replyPayloadToQueue(Message input) { return JmsResponse.forQueue(input.getPayload(), "queueOut"); } public JmsResponse replyPayloadToTopic(Message input) { return JmsResponse.forTopic(input.getPayload(), "topicOut"); } public JmsResponse replyPayloadToDestination(Message input) { return JmsResponse.forDestination(input.getPayload(), input.getHeaders().get("destination", Destination.class)); } public JmsResponse replyPayloadNoDestination(Message input) { return new JmsResponse<>(input.getPayload(), null); } public Message replyJackson(Message input) { return MessageBuilder.withPayload(createSampleResponse(input.getPayload())) .setHeader("foo", "bar").build(); } private SampleResponse createSampleResponse(String name) { return new SampleResponse(name, "lengthy description"); } public void fail(String input) { throw new IllegalArgumentException("Expected test exception"); } public void wrongParam(Integer i) { throw new IllegalArgumentException("Should not have been called"); } } private static class SampleResponse { private int counter = 42; private String name; private String description; public SampleResponse(String name, String description) { this.name = name; this.description = description; } public int getCounter() { return counter; } public void setCounter(int counter) { this.counter = counter; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } } }