/* * 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.xml.config; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import java.util.List; import org.junit.After; import org.junit.Test; import org.w3c.dom.Document; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.SmartLifecycle; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.router.AbstractMappingMessageRouter; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.support.SmartLifecycleRoleController; import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.xml.DefaultXmlPayloadConverter; import org.springframework.integration.xml.util.XmlTestUtil; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.PollableChannel; import org.springframework.messaging.support.GenericMessage; import org.springframework.test.context.ContextConfiguration; import org.springframework.util.MultiValueMap; /** * @author Jonas Partner * @author Mark Fisher * @author Oleg Zhurakousky * @author Gunnar Hillert * @author Gary Russell */ @ContextConfiguration public class XPathRouterParserTests { String channelConfig = "<si:channel id='test-input'/> <si:channel id='outputOne'><si:queue capacity='10'/></si:channel>" + "<si:channel id='defaultOutput'><si:queue capacity='10'/></si:channel>"; @Autowired @Qualifier("test-input") MessageChannel inputChannel; @Autowired @Qualifier("outputOne") QueueChannel outputChannel; @Autowired @Qualifier("defaultOutput") QueueChannel defaultOutput; ConfigurableApplicationContext appContext; public EventDrivenConsumer buildContext(String routerDef) { appContext = TestXmlApplicationContextHelper.getTestAppContext(channelConfig + routerDef); appContext.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); EventDrivenConsumer consumer = (EventDrivenConsumer) appContext.getBean("router"); consumer.start(); return consumer; } @After public void tearDown() { if (appContext != null) { appContext.close(); } } @Test public void testParse() throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("XPathRouterTests-context.xml", this.getClass()); EventDrivenConsumer consumer = (EventDrivenConsumer) context.getBean("parseOnly"); assertEquals(2, TestUtils.getPropertyValue(consumer, "handler.order")); assertEquals(123L, TestUtils.getPropertyValue(consumer, "handler.messagingTemplate.sendTimeout")); assertEquals(-1, TestUtils.getPropertyValue(consumer, "phase")); assertFalse(TestUtils.getPropertyValue(consumer, "autoStartup", Boolean.class)); SmartLifecycleRoleController roleController = context.getBean(SmartLifecycleRoleController.class); @SuppressWarnings("unchecked") List<SmartLifecycle> list = (List<SmartLifecycle>) TestUtils.getPropertyValue(roleController, "lifecycles", MultiValueMap.class).get("foo"); assertThat(list, contains((SmartLifecycle) consumer)); context.close(); } @Test public void testSimpleStringExpression() throws Exception { Document doc = XmlTestUtil.getDocumentForString("<name>outputOne</name>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); buildContext("<si-xml:xpath-router id='router' input-channel='test-input'><si-xml:xpath-expression expression='/name'/></si-xml:xpath-router>"); inputChannel.send(docMessage); assertEquals("Wrong number of messages", 1, outputChannel.getQueueSize()); } @Test public void testNamespacedStringExpression() throws Exception { Document doc = XmlTestUtil.getDocumentForString("<ns1:name xmlns:ns1='www.example.org'>outputOne</ns1:name>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); buildContext("<si-xml:xpath-router id='router' input-channel='test-input'><si-xml:xpath-expression expression='/ns2:name' ns-prefix='ns2' ns-uri='www.example.org' /></si-xml:xpath-router>"); inputChannel.send(docMessage); assertEquals("Wrong number of messages", 1, outputChannel.getQueueSize()); } @Test public void testStringExpressionWithNestedNamespaceMap() throws Exception { Document doc = XmlTestUtil.getDocumentForString( "<ns1:name xmlns:ns1='www.example.org' xmlns:ns2='www.example.org2'><ns2:type>outputOne</ns2:type></ns1:name>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); StringBuffer buffer = new StringBuffer( "<si-xml:xpath-router id='router' input-channel='test-input'><si-xml:xpath-expression expression='/ns1:name/ns2:type'> "); buffer.append("<map><entry key='ns1' value='www.example.org' /> <entry key='ns2' value='www.example.org2'/></map>"); buffer.append("</si-xml:xpath-expression></si-xml:xpath-router>"); buildContext(buffer.toString()); inputChannel.send(docMessage); assertEquals("Wrong number of messages", 1, outputChannel.getQueueSize()); } @Test public void testStringExpressionWithReferenceToNamespaceMap() throws Exception { Document doc = XmlTestUtil.getDocumentForString( "<ns1:name xmlns:ns1='www.example.org' xmlns:ns2='www.example.org2'><ns2:type>outputOne</ns2:type></ns1:name>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); StringBuffer buffer = new StringBuffer( "<si-xml:xpath-router id='router' input-channel='test-input'><si-xml:xpath-expression expression='/ns1:name/ns2:type' namespace-map='nsMap'/>"); buffer.append("</si-xml:xpath-router>"); buffer.append("<util:map id='nsMap'><entry key='ns1' value='www.example.org' /><entry key='ns2' value='www.example.org2' /></util:map>"); buildContext(buffer.toString()); inputChannel.send(docMessage); assertEquals("Wrong number of messages", 1, outputChannel.getQueueSize()); } @Test public void testSetResolutionRequiredFalse() throws Exception { StringBuffer contextBuffer = new StringBuffer("<si-xml:xpath-router id='router' resolution-required='false' input-channel='test-input'><si-xml:xpath-expression expression='/name'/></si-xml:xpath-router>"); EventDrivenConsumer consumer = buildContext(contextBuffer.toString()); DirectFieldAccessor accessor = new DirectFieldAccessor(consumer); Object handler = accessor.getPropertyValue("handler"); accessor = new DirectFieldAccessor(handler); Object resolutionRequired = accessor.getPropertyValue("resolutionRequired"); assertEquals("Resolution required not set to false ", false, resolutionRequired); } @Test public void testSetResolutionRequiredTrue() throws Exception { StringBuffer contextBuffer = new StringBuffer("<si-xml:xpath-router id='router' resolution-required='true' input-channel='test-input'><si-xml:xpath-expression expression='/name'/></si-xml:xpath-router>"); EventDrivenConsumer consumer = buildContext(contextBuffer.toString()); DirectFieldAccessor accessor = new DirectFieldAccessor(consumer); Object handler = accessor.getPropertyValue("handler"); accessor = new DirectFieldAccessor(handler); Object resolutionRequired = accessor.getPropertyValue("resolutionRequired"); assertEquals("Resolution required not set to true ", true, resolutionRequired); } @Test public void testSetDefaultOutputChannel() throws Exception { StringBuffer contextBuffer = new StringBuffer("<si-xml:xpath-router id='router' default-output-channel='defaultOutput' input-channel='test-input'><si-xml:xpath-expression expression='/name'/></si-xml:xpath-router>"); EventDrivenConsumer consumer = buildContext(contextBuffer.toString()); DirectFieldAccessor accessor = new DirectFieldAccessor(consumer); Object handler = accessor.getPropertyValue("handler"); accessor = new DirectFieldAccessor(handler); Object defaultOutputChannelValue = accessor.getPropertyValue("defaultOutputChannel"); assertEquals("Default output channel not correctly set ", defaultOutput, defaultOutputChannelValue); inputChannel.send(MessageBuilder.withPayload("<unrelated/>").build()); assertEquals("Wrong count of messages on default output channel", 1, defaultOutput.getQueueSize()); } @Test public void testWithDynamicChanges() throws Exception { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("XPathRouterTests-context.xml", this.getClass()); MessageChannel inputChannel = ac.getBean("xpathRouterEmptyChannel", MessageChannel.class); PollableChannel channelA = ac.getBean("channelA", PollableChannel.class); PollableChannel channelB = ac.getBean("channelB", PollableChannel.class); Document doc = XmlTestUtil.getDocumentForString("<name>channelA</name>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); inputChannel.send(docMessage); assertNotNull(channelA.receive(10)); assertNull(channelB.receive(10)); EventDrivenConsumer routerEndpoint = ac.getBean("xpathRouterEmpty", EventDrivenConsumer.class); AbstractMappingMessageRouter xpathRouter = (AbstractMappingMessageRouter) TestUtils.getPropertyValue(routerEndpoint, "handler"); xpathRouter.setChannelMapping("channelA", "channelB"); inputChannel.send(docMessage); assertNotNull(channelB.receive(10)); assertNull(channelA.receive(10)); ac.close(); } @Test public void testWithDynamicChangesWithExistingMappings() throws Exception { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("XPathRouterTests-context.xml", this.getClass()); MessageChannel inputChannel = ac.getBean("xpathRouterWithMappingChannel", MessageChannel.class); PollableChannel channelA = ac.getBean("channelA", PollableChannel.class); PollableChannel channelB = ac.getBean("channelB", PollableChannel.class); Document doc = XmlTestUtil.getDocumentForString("<name>channelA</name>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); inputChannel.send(docMessage); assertNull(channelA.receive(10)); assertNotNull(channelB.receive(10)); EventDrivenConsumer routerEndpoint = ac.getBean("xpathRouterWithMapping", EventDrivenConsumer.class); AbstractMappingMessageRouter xpathRouter = (AbstractMappingMessageRouter) TestUtils.getPropertyValue(routerEndpoint, "handler"); xpathRouter.removeChannelMapping("channelA"); inputChannel.send(docMessage); assertNotNull(channelA.receive(10)); assertNull(channelB.receive(10)); ac.close(); } @Test public void testWithDynamicChangesWithExistingMappingsAndMultiChannel() throws Exception { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("XPathRouterTests-context.xml", this.getClass()); MessageChannel inputChannel = ac.getBean("multiChannelRouterChannel", MessageChannel.class); PollableChannel channelA = ac.getBean("channelA", PollableChannel.class); PollableChannel channelB = ac.getBean("channelB", PollableChannel.class); Document doc = XmlTestUtil.getDocumentForString("<root><name>channelA</name><name>channelB</name></root>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); inputChannel.send(docMessage); assertNotNull(channelA.receive(10)); assertNotNull(channelA.receive(10)); assertNull(channelB.receive(10)); EventDrivenConsumer routerEndpoint = ac.getBean("xpathRouterWithMappingMultiChannel", EventDrivenConsumer.class); AbstractMappingMessageRouter xpathRouter = (AbstractMappingMessageRouter) TestUtils.getPropertyValue(routerEndpoint, "handler"); xpathRouter.removeChannelMapping("channelA"); xpathRouter.removeChannelMapping("channelB"); inputChannel.send(docMessage); assertNotNull(channelA.receive(10)); assertNotNull(channelB.receive(10)); ac.close(); } @Test public void testWithStringEvaluationType() throws Exception { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("XPathRouterTests-context.xml", this.getClass()); MessageChannel inputChannel = ac.getBean("xpathStringChannel", MessageChannel.class); PollableChannel channelA = ac.getBean("channelA", PollableChannel.class); Document doc = XmlTestUtil.getDocumentForString("<channelA/>"); GenericMessage<Document> docMessage = new GenericMessage<Document>(doc); inputChannel.send(docMessage); assertNotNull(channelA.receive(10)); ac.close(); } @Test public void testWithCustomXmlPayloadConverter() throws Exception { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("XPathRouterTests-context.xml", this.getClass()); MessageChannel inputChannel = ac.getBean("customConverterChannel", MessageChannel.class); PollableChannel channelZ = ac.getBean("channelZ", PollableChannel.class); GenericMessage<String> message = new GenericMessage<String>("<name>channelA</name>"); inputChannel.send(message); Message<?> result = channelZ.receive(0); assertNotNull(result); assertEquals("<name>channelA</name>", result.getPayload()); ac.close(); } @SuppressWarnings("unused") private static class TestXmlPayloadConverter extends DefaultXmlPayloadConverter { @Override public Document convertToDocument(Object object) { if (object instanceof String) { object = ((String) object).replace("A", "Z"); } return super.convertToDocument(object); } } }