View Javadoc

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