1   /*
2    * $Id: FilteringXmlMessageSplitterTestCase.java 12370 2008-07-17 13:11:17Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.MuleMessage;
15  import org.mule.api.MuleSession;
16  import org.mule.api.endpoint.OutboundEndpoint;
17  import org.mule.module.xml.routing.FilteringXmlMessageSplitter;
18  import org.mule.module.xml.util.XMLTestUtils;
19  import org.mule.tck.AbstractMuleTestCase;
20  import org.mule.tck.MuleTestUtils;
21  import org.mule.util.IOUtils;
22  
23  import com.mockobjects.constraint.Constraint;
24  import com.mockobjects.dynamic.C;
25  import com.mockobjects.dynamic.Mock;
26  
27  import java.io.InputStream;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  
33  import javax.xml.parsers.DocumentBuilderFactory;
34  
35  import org.dom4j.Document;
36  import org.dom4j.DocumentHelper;
37  
38  public class FilteringXmlMessageSplitterTestCase extends AbstractMuleTestCase
39  {
40      private OutboundEndpoint endpoint1;
41      private OutboundEndpoint endpoint2;
42      private OutboundEndpoint endpoint3;
43      private FilteringXmlMessageSplitter xmlSplitter;
44  
45      // @Override
46      protected void doSetUp() throws Exception
47      {
48          // setup endpoints
49          endpoint1 = getTestOutboundEndpoint("Test1Endpoint", "test://endpointUri.1");
50          endpoint2 = getTestOutboundEndpoint("Test2Endpoint", "test://endpointUri.2");
51          endpoint3 = getTestOutboundEndpoint("Test3Endpoint", "test://endpointUri.3");
52  
53          // setup splitter
54          xmlSplitter = new FilteringXmlMessageSplitter();
55          xmlSplitter.setValidateSchema(true);
56          xmlSplitter.setExternalSchemaLocation("purchase-order.xsd");
57  
58          // The xml document declares a default namespace, thus
59          // we need to workaround it by specifying it both in
60          // the namespaces and in the splitExpression
61          Map namespaces = new HashMap();
62          namespaces.put("e", "http://www.example.com");
63          xmlSplitter.setSplitExpression("/e:purchaseOrder/e:items/e:item");
64          xmlSplitter.setNamespaces(namespaces);
65          xmlSplitter.addEndpoint(endpoint1);
66          xmlSplitter.addEndpoint(endpoint2);
67          xmlSplitter.addEndpoint(endpoint3);
68      }
69  
70      public void testStringPayloadXmlMessageSplitter() throws Exception
71      {
72          String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
73          internalTestSuccessfulXmlSplitter(payload);
74          internalTestSuccessfulXmlSplitter2(payload);
75      }
76  
77      public void testStringPayloadXmlMessageSplitterWithoutXsd() throws Exception
78      {
79          xmlSplitter.setExternalSchemaLocation(null);
80          xmlSplitter.setValidateSchema(false);
81          String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
82          internalTestSuccessfulXmlSplitter(payload);
83          internalTestSuccessfulXmlSplitter2(payload);
84      }
85  
86      public void testDom4JDocumentPayloadXmlMessageSplitter() throws Exception
87      {
88          String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
89          Document doc = DocumentHelper.parseText(payload);
90          internalTestSuccessfulXmlSplitter(doc);
91          internalTestSuccessfulXmlSplitter2(doc);
92      }
93  
94  // TODO MULE-3554
95  //    public void testW3CDocumentPayloadXmlMessageSplitter() throws Exception
96  //    {
97  //        InputStream is = IOUtils.getResourceAsStream("purchase-order.xml", getClass());
98  //        org.w3c.dom.Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
99  //        internalTestSuccessfulXmlSplitter(doc);
100 //        internalTestSuccessfulXmlSplitter2(doc);
101 //    }
102 
103     public void testByteArrayPayloadXmlMessageSplitter() throws Exception
104     {
105         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
106         internalTestSuccessfulXmlSplitter(payload.getBytes());
107         internalTestSuccessfulXmlSplitter2(payload.getBytes());
108     }
109 
110     public void testByteArrayPayloadCorrelateNever() throws Exception
111     {
112         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
113         xmlSplitter.setEnableCorrelation(AbstractOutboundRouter.ENABLE_CORRELATION_NEVER);
114         internalTestSuccessfulXmlSplitter(payload.getBytes());
115         internalTestSuccessfulXmlSplitter2(payload.getBytes());
116     }
117 
118     public void testXmlMessageVariants() throws Exception
119     {
120         List list = XMLTestUtils.getXmlMessageVariants("purchase-order.xml");
121         Iterator it = list.iterator();
122         
123         Object msg;
124         while (it.hasNext())
125         {
126             msg = it.next();
127             // TODO MULE-3554 Not working for W3C Documents, see testW3CDocumentPayloadXmlMessageSplitter()
128             if (!(msg instanceof org.w3c.dom.Document))
129             {
130                 internalTestSuccessfulXmlSplitter(msg);
131             }
132         }
133     }
134 
135     public void testXmlMessageVariants2() throws Exception
136     {
137         List list = XMLTestUtils.getXmlMessageVariants("purchase-order.xml");
138         Iterator it = list.iterator();
139         
140         Object msg;
141         while (it.hasNext())
142         {
143             msg = it.next();
144             // TODO MULE-3554 Not working for W3C Documents, see testW3CDocumentPayloadXmlMessageSplitter()
145             if (!(msg instanceof org.w3c.dom.Document))
146             {
147                 internalTestSuccessfulXmlSplitter2(msg);
148             }
149         }
150     }
151 
152     private void internalTestSuccessfulXmlSplitter(Object payload) throws Exception
153     {
154         Mock session = MuleTestUtils.getMockSession();
155         session.matchAndReturn("getService", getTestService());
156 
157         MuleMessage message = new DefaultMuleMessage(payload);
158 
159         assertTrue(xmlSplitter.isMatch(message));
160         final ItemNodeConstraint itemNodeConstraint = new ItemNodeConstraint();
161         session.expect("dispatchEvent", C.args(itemNodeConstraint, C.eq(endpoint1)));
162         session.expect("dispatchEvent", C.args(itemNodeConstraint, C.eq(endpoint1)));
163         xmlSplitter.route(message, (MuleSession)session.proxy(), false);
164         session.verify();
165     }
166 
167     // Note: these used to be a single method but I split them up because if the message is an 
168     // InputStream it can't be routed (read) more than once.
169     private void internalTestSuccessfulXmlSplitter2(Object payload) throws Exception
170     {
171         Mock session = MuleTestUtils.getMockSession();
172         session.matchAndReturn("getService", getTestService());
173 
174         MuleMessage message = new DefaultMuleMessage(payload);
175 
176         assertTrue(xmlSplitter.isMatch(message));
177         final ItemNodeConstraint itemNodeConstraint = new ItemNodeConstraint();
178 
179         session.expectAndReturn("sendEvent", C.args(itemNodeConstraint, C.eq(endpoint1)), message);
180         session.expectAndReturn("sendEvent", C.args(itemNodeConstraint, C.eq(endpoint1)), message);
181         MuleMessage result = xmlSplitter.route(message, (MuleSession)session.proxy(), true);
182         assertNotNull(result);
183         assertEquals(message, result);
184         session.verify();
185     }
186 
187     public void testXsdNotFoundThrowsException() throws Exception
188     {
189         final String invalidSchemaLocation = "non-existent.xsd";
190         Mock session = MuleTestUtils.getMockSession();
191 
192         FilteringXmlMessageSplitter splitter = new FilteringXmlMessageSplitter();
193         splitter.setValidateSchema(true);
194         splitter.setExternalSchemaLocation(invalidSchemaLocation);
195 
196         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
197 
198         MuleMessage message = new DefaultMuleMessage(payload);
199 
200         assertTrue(splitter.isMatch(message));
201         try
202         {
203             splitter.route(message, (MuleSession)session.proxy(), false);
204             fail("Should have thrown an exception, because XSD is not found.");
205         }
206         catch (IllegalArgumentException iaex)
207         {
208             assertTrue("Wrong exception?", iaex.getMessage().indexOf(
209                     "Couldn't find schema at " + invalidSchemaLocation) != -1);
210         }
211         session.verify();
212     }
213 
214     public void testUnsupportedTypePayloadIsIgnored() throws Exception
215     {
216         Exception unsupportedPayload = new Exception();
217 
218         Mock session = MuleTestUtils.getMockSession();
219 
220         MuleMessage message = new DefaultMuleMessage(unsupportedPayload);
221 
222         assertTrue(xmlSplitter.isMatch(message));
223         xmlSplitter.route(message, (MuleSession)session.proxy(), false);
224         session.verify();
225 
226         message = new DefaultMuleMessage(unsupportedPayload);
227 
228         MuleMessage result = xmlSplitter.route(message, (MuleSession)session.proxy(), true);
229         assertNull(result);
230         session.verify();
231     }
232 
233     public void testInvalidXmlPayloadThrowsException() throws Exception
234     {
235         Mock session = MuleTestUtils.getMockSession();
236 
237         FilteringXmlMessageSplitter splitter = new FilteringXmlMessageSplitter();
238 
239         MuleMessage message = new DefaultMuleMessage("This is not XML.");
240 
241         try
242         {
243             splitter.route(message, (MuleSession)session.proxy(), false);
244             fail("No exception thrown.");
245         }
246         catch (IllegalArgumentException iaex)
247         {
248             assertTrue("Wrong exception message.", iaex.getMessage().startsWith(
249                     "Failed to initialise the payload: "));
250         }
251 
252     }
253 
254     private class ItemNodeConstraint implements Constraint
255     {
256         public boolean eval(Object o)
257         {
258             final MuleMessage message = (MuleMessage)o;
259             final Object payload = message.getPayload();
260             assertTrue("Wrong class type for node.", payload instanceof Document);
261 
262             // MULE-2963
263             if (xmlSplitter.enableCorrelation == AbstractOutboundRouter.ENABLE_CORRELATION_NEVER)
264             {
265                 assertEquals(-1, message.getCorrelationGroupSize());                
266             }
267             else
268             {
269                 // the purchase order document contains two parts
270                 assertEquals(2, message.getCorrelationGroupSize());
271             }
272 
273             Document node = (Document) payload;
274             final String partNumber = node.getRootElement().attributeValue("partNum");
275             return "872-AA".equals(partNumber) || "926-AA".equals(partNumber);
276         }
277     }
278 }