/*
* Copyright 2002-2016 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.integration.jms.config;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.lang.reflect.Method;
import java.util.Properties;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.Queue;
import javax.jms.Session;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.NotReadablePropertyException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.Expression;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.endpoint.PollingConsumer;
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.jms.JmsOutboundGateway;
import org.springframework.integration.jms.StubMessageConverter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Jonas Partner
* @author Oleg Zhurakousky
* @author Mark Fisher
* @author Gary Russell
*/
public class JmsOutboundGatewayParserTests {
private static volatile int adviceCalled;
@Test
public void testWithDeliveryPersistentAttribute() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayWithDeliveryPersistent.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("jmsGateway");
DirectFieldAccessor accessor = new DirectFieldAccessor(endpoint);
JmsOutboundGateway gateway = (JmsOutboundGateway) accessor.getPropertyValue("handler");
accessor = new DirectFieldAccessor(gateway);
int deliveryMode = (Integer) accessor.getPropertyValue("deliveryMode");
assertEquals(DeliveryMode.PERSISTENT, deliveryMode);
assertTrue(TestUtils.getPropertyValue(gateway, "async", Boolean.class));
DefaultMessageListenerContainer container = TestUtils.getPropertyValue(gateway, "replyContainer",
DefaultMessageListenerContainer.class);
assertEquals(4, TestUtils.getPropertyValue(container, "concurrentConsumers"));
assertEquals(5, TestUtils.getPropertyValue(container, "maxConcurrentConsumers"));
assertEquals(10, TestUtils.getPropertyValue(container, "maxMessagesPerTask"));
assertEquals(2000L, TestUtils.getPropertyValue(container, "receiveTimeout"));
Object recoveryInterval;
try {
recoveryInterval = TestUtils.getPropertyValue(container, "recoveryInterval");
}
catch (NotReadablePropertyException e) {
recoveryInterval = TestUtils.getPropertyValue(container, "backOff.interval");
}
assertEquals(10000L, recoveryInterval);
assertEquals(7, TestUtils.getPropertyValue(container, "idleConsumerLimit"));
assertEquals(2, TestUtils.getPropertyValue(container, "idleTaskExecutionLimit"));
assertEquals(3, TestUtils.getPropertyValue(container, "cacheLevel"));
assertTrue(container.isSessionTransacted());
assertSame(context.getBean("exec"), TestUtils.getPropertyValue(container, "taskExecutor"));
assertEquals(1234000L, TestUtils.getPropertyValue(gateway, "idleReplyContainerTimeout"));
context.close();
}
@Test
public void testAdvised() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayWithDeliveryPersistent.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("advised");
JmsOutboundGateway gateway = TestUtils.getPropertyValue(endpoint, "handler", JmsOutboundGateway.class);
assertFalse(TestUtils.getPropertyValue(gateway, "async", Boolean.class));
gateway.handleMessage(new GenericMessage<String>("foo"));
assertEquals(1, adviceCalled);
assertEquals(3, TestUtils.getPropertyValue(gateway, "replyContainer.sessionAcknowledgeMode"));
context.close();
}
@Test
public void testDefault() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayWithConverter.xml", this.getClass());
PollingConsumer endpoint = (PollingConsumer) context.getBean("jmsGateway");
DirectFieldAccessor accessor = new DirectFieldAccessor(endpoint);
JmsOutboundGateway gateway = (JmsOutboundGateway) accessor.getPropertyValue("handler");
accessor = new DirectFieldAccessor(gateway);
MessageConverter converter = (MessageConverter) accessor.getPropertyValue("messageConverter");
assertTrue("Wrong message converter", converter instanceof StubMessageConverter);
context.close();
}
@Test
public void gatewayWithOrder() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayWithOrder.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("jmsGateway");
DirectFieldAccessor accessor = new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
Object order = accessor.getPropertyValue("order");
assertEquals(99, order);
assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
context.close();
}
@Test
public void gatewayWithDest() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayReplyDestOptions.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("jmsGatewayDest");
DirectFieldAccessor accessor = new DirectFieldAccessor(endpoint);
JmsOutboundGateway gateway = (JmsOutboundGateway) accessor.getPropertyValue("handler");
accessor = new DirectFieldAccessor(gateway);
assertSame(context.getBean("replyQueue"), accessor.getPropertyValue("replyDestination"));
context.close();
}
@Test
public void gatewayWithDestName() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayReplyDestOptions.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("jmsGatewayDestName");
DirectFieldAccessor accessor = new DirectFieldAccessor(endpoint);
JmsOutboundGateway gateway = (JmsOutboundGateway) accessor.getPropertyValue("handler");
accessor = new DirectFieldAccessor(gateway);
assertEquals("replyQueueName", accessor.getPropertyValue("replyDestinationName"));
context.close();
}
@Test
public void gatewayWithDestExpression() throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayReplyDestOptions.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("jmsGatewayDestExpression");
DirectFieldAccessor accessor = new DirectFieldAccessor(endpoint);
JmsOutboundGateway gateway = (JmsOutboundGateway) accessor.getPropertyValue("handler");
ExpressionEvaluatingMessageProcessor<?> processor = TestUtils.getPropertyValue(gateway, "replyDestinationExpressionProcessor",
ExpressionEvaluatingMessageProcessor.class);
Expression expression = TestUtils.getPropertyValue(gateway, "replyDestinationExpressionProcessor.expression",
Expression.class);
assertEquals("payload", expression.getExpressionString());
Message<?> message = MessageBuilder.withPayload("foo").build();
assertEquals("foo", processor.processMessage(message));
Method method = JmsOutboundGateway.class.getDeclaredMethod("determineReplyDestination", Message.class, Session.class);
method.setAccessible(true);
Session session = mock(Session.class);
Queue queue = mock(Queue.class);
when(session.createQueue("foo")).thenReturn(queue);
Destination replyQ = (Destination) method.invoke(gateway, message, session);
assertSame(queue, replyQ);
context.close();
}
@Test
public void gatewayWithDestBeanRefExpression() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayReplyDestOptions.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("jmsGatewayDestExpressionBeanRef");
DirectFieldAccessor accessor = new DirectFieldAccessor(endpoint);
JmsOutboundGateway gateway = (JmsOutboundGateway) accessor.getPropertyValue("handler");
ExpressionEvaluatingMessageProcessor<?> processor = TestUtils.getPropertyValue(gateway, "replyDestinationExpressionProcessor",
ExpressionEvaluatingMessageProcessor.class);
Expression expression = TestUtils.getPropertyValue(gateway, "replyDestinationExpressionProcessor.expression",
Expression.class);
assertEquals("@replyQueue", expression.getExpressionString());
assertSame(context.getBean("replyQueue"), processor.processMessage(null));
context.close();
}
@Test
public void gatewayWithDestAndDestExpression() {
try {
new ClassPathXmlApplicationContext(
"jmsOutboundGatewayReplyDestOptions-fail.xml", this.getClass()).close();
fail("Exception expected");
}
catch (BeanDefinitionParsingException e) {
assertTrue(e.getMessage().startsWith("Configuration problem: Only one of the " +
"'replyQueue', 'reply-destination-name', or 'reply-destination-expression' attributes is allowed."));
}
}
@Test
public void gatewayMaintainsReplyChannelAndInboundHistory() {
ActiveMqTestUtils.prepare();
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"gatewayMaintainsReplyChannel.xml", this.getClass());
SampleGateway gateway = context.getBean("gateway", SampleGateway.class);
SubscribableChannel jmsInput = context.getBean("jmsInput", SubscribableChannel.class);
MessageHandler handler = message -> {
MessageHistory history = MessageHistory.read(message);
assertNotNull(history);
Properties componentHistoryRecord = TestUtils.locateComponentInHistory(history, "inboundGateway", 0);
assertNotNull(componentHistoryRecord);
assertEquals("jms:inbound-gateway", componentHistoryRecord.get("type"));
MessagingTemplate messagingTemplate = new MessagingTemplate();
messagingTemplate.setDefaultDestination((MessageChannel) message.getHeaders().getReplyChannel());
messagingTemplate.send(message);
};
jmsInput.subscribe(handler);
String result = gateway.echo("hello");
assertEquals("hello", result);
JmsOutboundGateway gw1 = context.getBean("chain1$child.gateway.handler", JmsOutboundGateway.class);
MessageChannel out = TestUtils.getPropertyValue(gw1, "outputChannel", MessageChannel.class);
assertThat(out.getClass().getSimpleName(), equalTo("ReplyForwardingMessageChannel"));
JmsOutboundGateway gw2 = context.getBean("chain2$child.gateway.handler", JmsOutboundGateway.class);
out = TestUtils.getPropertyValue(gw2, "outputChannel", MessageChannel.class);
assertThat(out.getClass().getName(), containsString("MessageHandlerChain$"));
context.close();
}
@Test
public void gatewayWithDefaultPubSubDomain() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayWithPubSubSettings.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("defaultGateway");
DirectFieldAccessor accessor = new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
assertFalse((Boolean) accessor.getPropertyValue("requestPubSubDomain"));
assertFalse((Boolean) accessor.getPropertyValue("replyPubSubDomain"));
context.close();
}
@Test
public void gatewayWithExplicitPubSubDomainTrue() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsOutboundGatewayWithPubSubSettings.xml", this.getClass());
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("pubSubDomainGateway");
DirectFieldAccessor accessor = new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
assertTrue((Boolean) accessor.getPropertyValue("requestPubSubDomain"));
assertTrue((Boolean) accessor.getPropertyValue("replyPubSubDomain"));
context.close();
}
public interface SampleGateway {
String echo(String value);
}
public static class SampleService {
public String echo(String value) {
return value.toUpperCase();
}
}
public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
adviceCalled++;
return null;
}
}
}