View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.routing.outbound;
8   
9   import org.mule.DefaultMuleMessage;
10  import org.mule.api.MuleEvent;
11  import org.mule.api.MuleMessage;
12  import org.mule.api.MuleMessageCollection;
13  import org.mule.api.MuleSession;
14  import org.mule.api.config.MuleProperties;
15  import org.mule.api.endpoint.OutboundEndpoint;
16  import org.mule.module.xml.routing.XmlMessageSplitter;
17  import org.mule.module.xml.util.NamespaceManager;
18  import org.mule.module.xml.util.XMLUtils;
19  import org.mule.routing.CorrelationMode;
20  import org.mule.tck.MuleTestUtils;
21  import org.mule.tck.junit4.AbstractMuleContextTestCase;
22  import org.mule.util.IOUtils;
23  
24  import com.mockobjects.constraint.Constraint;
25  import com.mockobjects.dynamic.Mock;
26  
27  import java.util.HashMap;
28  import java.util.Map;
29  
30  import javax.xml.stream.XMLInputFactory;
31  import javax.xml.transform.Source;
32  import javax.xml.transform.Transformer;
33  import javax.xml.transform.dom.DOMResult;
34  
35  import org.dom4j.Document;
36  import org.dom4j.DocumentHelper;
37  import org.junit.Test;
38  
39  import static org.junit.Assert.assertEquals;
40  import static org.junit.Assert.assertNotNull;
41  import static org.junit.Assert.assertTrue;
42  import static org.junit.Assert.fail;
43  
44  public class XmlMessageSplitterTestCase extends AbstractMuleContextTestCase
45  {
46      private OutboundEndpoint endpoint1;
47      private OutboundEndpoint endpoint2;
48      private OutboundEndpoint endpoint3;
49      private OutboundEndpoint endpoint4;
50      private OutboundEndpoint endpoint5;
51      private OutboundEndpoint endpoint6;
52      private Mock mockendpoint1;
53      private Mock mockendpoint2;
54      private Mock mockendpoint3;
55      private Mock mockendpoint4;
56      private Mock mockendpoint5;
57      private Mock mockendpoint6;
58      private XmlMessageSplitter asyncXmlSplitter;
59      private XmlMessageSplitter syncXmlSplitter;
60  
61      @Override
62      protected void doSetUp() throws Exception
63      {
64          // setup sync targets
65          endpoint1 = getTestOutboundEndpoint("Test1Endpoint", "test://endpointUri.1");
66          endpoint2 = getTestOutboundEndpoint("Test2Endpoint", "test://endpointUri.2");
67          endpoint3 = getTestOutboundEndpoint("Test3Endpoint", "test://endpointUri.3");
68          mockendpoint1 = RouterTestUtils.getMockEndpoint(endpoint1);
69          mockendpoint2 = RouterTestUtils.getMockEndpoint(endpoint2);
70          mockendpoint3 = RouterTestUtils.getMockEndpoint(endpoint3);
71  
72          // setup async targets
73          endpoint4 = getTestOutboundEndpoint("Test1Endpoint", "test://endpointUri.1?exchangePattern=request-response");
74          endpoint5 = getTestOutboundEndpoint("Test2Endpoint", "test://endpointUri.2?exchangePattern=request-response");
75          endpoint6 = getTestOutboundEndpoint("Test3Endpoint", "test://endpointUri.3?exchangePattern=request-response");
76          mockendpoint4 = RouterTestUtils.getMockEndpoint(endpoint4);
77          mockendpoint5 = RouterTestUtils.getMockEndpoint(endpoint5);
78          mockendpoint6 = RouterTestUtils.getMockEndpoint(endpoint6);
79  
80          // setup sync splitter
81          syncXmlSplitter = new XmlMessageSplitter();
82          syncXmlSplitter.setValidateSchema(true);
83          syncXmlSplitter.setExternalSchemaLocation("purchase-order.xsd");
84  
85          // The xml document declares a default namespace, thus
86          // we need to workaround it by specifying it both in
87          // the namespaces and in the splitExpression
88          Map namespaces = new HashMap();
89          namespaces.put("e", "http://www.example.com");
90          syncXmlSplitter.setSplitExpression("/e:purchaseOrder/e:items/e:item");
91          syncXmlSplitter.setNamespaces(namespaces);
92          syncXmlSplitter.addRoute((OutboundEndpoint) mockendpoint4.proxy());
93          syncXmlSplitter.addRoute((OutboundEndpoint) mockendpoint5.proxy());
94          syncXmlSplitter.addRoute((OutboundEndpoint) mockendpoint6.proxy());
95  
96          // setup async splitter
97          asyncXmlSplitter = new XmlMessageSplitter();
98          asyncXmlSplitter.setValidateSchema(true);
99          asyncXmlSplitter.setExternalSchemaLocation("purchase-order.xsd");
100 
101         asyncXmlSplitter.setSplitExpression("/e:purchaseOrder/e:items/e:item");
102         asyncXmlSplitter.setNamespaces(namespaces);
103         asyncXmlSplitter.addRoute((OutboundEndpoint) mockendpoint1.proxy());
104         asyncXmlSplitter.addRoute((OutboundEndpoint) mockendpoint2.proxy());
105         asyncXmlSplitter.addRoute((OutboundEndpoint) mockendpoint3.proxy());
106 
107         syncXmlSplitter.setMuleContext(muleContext);
108         asyncXmlSplitter.setMuleContext(muleContext);
109         syncXmlSplitter.initialise();
110         asyncXmlSplitter.initialise();
111     }
112 
113     @Test
114     public void testStringPayloadXmlMessageSplitter() throws Exception
115     {
116         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
117         internalTestSuccessfulXmlSplitter(payload);
118     }
119 
120     @Test
121     public void testStringPayloadXmlMessageSplitterWithoutXsd() throws Exception
122     {
123         syncXmlSplitter.setExternalSchemaLocation(null);
124         syncXmlSplitter.setValidateSchema(false);
125         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
126         internalTestSuccessfulXmlSplitter(payload);
127     }
128 
129     @Test
130     public void testDom4JDocumentPayloadXmlMessageSplitter() throws Exception
131     {
132         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
133         Document doc = DocumentHelper.parseText(payload);
134         internalTestSuccessfulXmlSplitter(doc);
135     }
136 
137     @Test
138     public void testW3CDocumentPayloadXmlMessageSplitter() throws Exception
139     {
140         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
141         Source sourceDoc = XMLUtils.toXmlSource( XMLInputFactory.newInstance(), true, payload);
142         DOMResult result = new DOMResult();
143         Transformer transformer = XMLUtils.getTransformer();
144         transformer.transform(sourceDoc, result);
145         internalTestSuccessfulXmlSplitter(result.getNode());
146     }
147 
148     @Test
149     public void testByteArrayPayloadXmlMessageSplitter() throws Exception
150     {
151         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
152         internalTestSuccessfulXmlSplitter(payload.getBytes());
153     }
154 
155     @Test
156     public void testByteArrayPayloadCorrelateNever() throws Exception
157     {
158         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
159         syncXmlSplitter.setEnableCorrelation(CorrelationMode.NEVER);
160         asyncXmlSplitter.setEnableCorrelation(CorrelationMode.NEVER);
161         internalTestSuccessfulXmlSplitter(payload.getBytes());
162     }
163 
164     private void internalTestSuccessfulXmlSplitter(Object payload) throws Exception
165     {
166         Mock session = MuleTestUtils.getMockSession();
167         session.matchAndReturn("getFlowConstruct", getTestService());
168         session.matchAndReturn("setFlowConstruct", RouterTestUtils.getArgListCheckerFlowConstruct(), null);
169         MuleMessage message = new DefaultMuleMessage(payload, muleContext);
170 
171         assertTrue(asyncXmlSplitter.isMatch(message));
172         final ItemNodeConstraint itemNodeConstraint = new ItemNodeConstraint();
173         mockendpoint1.expect("process", RouterTestUtils.getArgListCheckerMuleEvent());
174         mockendpoint2.expect("process", RouterTestUtils.getArgListCheckerMuleEvent());
175         asyncXmlSplitter.route(new OutboundRoutingTestEvent(message, (MuleSession) session.proxy()));
176         mockendpoint1.verify();
177         mockendpoint2.verify();
178 
179         message = new DefaultMuleMessage(payload, muleContext);
180         MuleEvent event = new OutboundRoutingTestEvent(message, null);
181         mockendpoint4.expectAndReturn("process", RouterTestUtils.getArgListCheckerMuleEvent(), event);
182         mockendpoint5.expectAndReturn("process", RouterTestUtils.getArgListCheckerMuleEvent(), event);
183         MuleEvent result = syncXmlSplitter.route(new OutboundRoutingTestEvent(message, (MuleSession) session.proxy()));
184         MuleMessage resultMessage = result.getMessage();
185         assertNotNull(resultMessage);
186         assertNotNull(result);
187         assertTrue(resultMessage instanceof MuleMessageCollection);
188         assertEquals(2, ((MuleMessageCollection) resultMessage).size());
189         mockendpoint4.verify();
190         mockendpoint5.verify();
191     }
192 
193     @Test
194     public void testXsdNotFoundThrowsException() throws Exception
195     {
196         final String invalidSchemaLocation = "non-existent.xsd";
197         Mock session = MuleTestUtils.getMockSession();
198         session.matchAndReturn("getFlowConstruct", getTestService());
199 
200         XmlMessageSplitter splitter = new XmlMessageSplitter();
201         splitter.setValidateSchema(true);
202         splitter.setExternalSchemaLocation(invalidSchemaLocation);
203 
204         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
205 
206         MuleMessage message = new DefaultMuleMessage(payload, muleContext);
207 
208         assertTrue(splitter.isMatch(message));
209         try
210         {
211             splitter.route(new OutboundRoutingTestEvent(message, (MuleSession) session.proxy()));
212             fail("Should have thrown an exception, because XSD is not found.");
213         }
214         catch (IllegalArgumentException iaex)
215         {
216             assertTrue("Wrong exception?", iaex.getMessage().indexOf(
217                     "Couldn't find schema at " + invalidSchemaLocation) != -1);
218         }
219         session.verify();
220     }
221 
222 
223     @Test
224     public void testInvalidPayloadTypeThrowsException() throws Exception
225     {
226         Mock session = MuleTestUtils.getMockSession();
227         session.matchAndReturn("getFlowConstruct", getTestService());
228 
229         XmlMessageSplitter splitter = new XmlMessageSplitter();
230 
231         MuleMessage message = new DefaultMuleMessage(new Exception(), muleContext);
232 
233         try
234         {
235             splitter.route(new OutboundRoutingTestEvent(message, (MuleSession) session.proxy()));
236             fail("No exception thrown.");
237         }
238         catch (IllegalArgumentException iaex)
239         {
240             assertTrue("Wrong exception message.", iaex.getMessage().startsWith(
241                     "Failed to initialise the payload: "));
242         }
243     }
244 
245     @Test
246     public void testInvalidXmlPayloadThrowsException() throws Exception
247     {
248         Mock session = MuleTestUtils.getMockSession();
249         session.matchAndReturn("getFlowConstruct", getTestService());
250 
251         XmlMessageSplitter splitter = new XmlMessageSplitter();
252 
253         MuleMessage message = new DefaultMuleMessage("This is not XML.", muleContext);
254 
255         try
256         {
257             splitter.route(new OutboundRoutingTestEvent(message, (MuleSession) session.proxy()));
258             fail("No exception thrown.");
259         }
260         catch (IllegalArgumentException iaex)
261         {
262             assertTrue("Wrong exception message.", iaex.getMessage().startsWith(
263                     "Failed to initialise the payload: "));
264         }
265     }
266 
267     @Test
268     public void testGlobalNamespaceManagerLookup() throws Exception
269     {
270         // clear any configured namespaces
271         syncXmlSplitter.setNamespaces(null);
272         asyncXmlSplitter.setNamespaces(null);
273 
274         // configure a global namespace manager
275         NamespaceManager namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
276         if (namespaceManager == null)
277         {
278             namespaceManager = new NamespaceManager();
279             muleContext.getRegistry().registerObject(MuleProperties.OBJECT_MULE_NAMESPACE_MANAGER, namespaceManager);
280         }
281         Map namespaces = new HashMap();
282         namespaces.put("e", "http://www.example.com");
283         syncXmlSplitter.setSplitExpression("/e:purchaseOrder/e:items/e:item");
284         asyncXmlSplitter.setSplitExpression("/e:purchaseOrder/e:items/e:item");
285         namespaceManager.setNamespaces(namespaces);
286 
287         // re-init splitters
288         syncXmlSplitter.initialise();
289         asyncXmlSplitter.initialise();
290 
291         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
292         internalTestSuccessfulXmlSplitter(payload);
293     }
294 
295     private class ItemNodeConstraint implements Constraint
296     {
297         public boolean eval(Object o)
298         {
299             final MuleMessage message = (MuleMessage) o;
300             final Object payload = message.getPayload();
301             assertTrue("Wrong class type for node.", payload instanceof Document);
302 
303             // MULE-2963
304             if (syncXmlSplitter.enableCorrelation == CorrelationMode.NEVER
305                 || asyncXmlSplitter.enableCorrelation == CorrelationMode.NEVER)
306             {
307                 assertEquals(-1, message.getCorrelationGroupSize());
308             }
309             else
310             {
311                 // the purchase order document contains two parts
312                 assertEquals(2, message.getCorrelationGroupSize());
313             }
314 
315             Document node = (Document) payload;
316             final String partNumber = node.getRootElement().attributeValue("partNum");
317             return "872-AA".equals(partNumber) || "926-AA".equals(partNumber);
318         }
319     }
320 }