1   /*
2    * $Id: RoundRobinXmlSplitterTestCase.java 12181 2008-06-26 20:05:55Z dirk.olmes $
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.RoundRobinXmlSplitter;
18  import org.mule.tck.AbstractMuleTestCase;
19  import org.mule.tck.MuleTestUtils;
20  import org.mule.util.IOUtils;
21  
22  import com.mockobjects.constraint.Constraint;
23  import com.mockobjects.dynamic.C;
24  import com.mockobjects.dynamic.Mock;
25  
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.dom4j.Document;
30  import org.dom4j.DocumentHelper;
31  
32  public class RoundRobinXmlSplitterTestCase extends AbstractMuleTestCase
33  {
34      private OutboundEndpoint endpoint1;
35      private OutboundEndpoint endpoint2;
36      private OutboundEndpoint endpoint3;
37      private RoundRobinXmlSplitter xmlSplitter;
38  
39      // @Override
40      protected void doSetUp() throws Exception
41      {
42          // setup endpoints
43          endpoint1 = getTestOutboundEndpoint("Test1Endpoint", "test://endpointUri.1");
44          endpoint2 = getTestOutboundEndpoint("Test2Endpoint", "test://endpointUri.2");
45          endpoint3 = getTestOutboundEndpoint("Test3Endpoint", "test://endpointUri.3");
46  
47          // setup splitter
48          xmlSplitter = new RoundRobinXmlSplitter();
49          xmlSplitter.setValidateSchema(true);
50          xmlSplitter.setExternalSchemaLocation("purchase-order.xsd");
51  
52          // The xml document declares a default namespace, thus
53          // we need to workaround it by specifying it both in
54          // the namespaces and in the splitExpression
55          Map namespaces = new HashMap();
56          namespaces.put("e", "http://www.example.com");
57          xmlSplitter.setSplitExpression("/e:purchaseOrder/e:items/e:item");
58          xmlSplitter.setNamespaces(namespaces);
59          xmlSplitter.addEndpoint(endpoint1);
60          xmlSplitter.addEndpoint(endpoint2);
61          xmlSplitter.addEndpoint(endpoint3);
62      }
63  
64      public void testStringPayloadXmlMessageSplitter() throws Exception
65      {
66          String payload = IOUtils.getResourceAsString("purchase-order2.xml", getClass());
67          internalTestSuccessfulXmlSplitter(payload);
68      }
69  
70      public void testDom4JDocumentPayloadXmlMessageSplitter() throws Exception
71      {
72          String payload = IOUtils.getResourceAsString("purchase-order2.xml", getClass());
73          Document doc = DocumentHelper.parseText(payload);
74          internalTestSuccessfulXmlSplitter(doc);
75      }
76  
77      public void testByteArrayPayloadXmlMessageSplitter() throws Exception
78      {
79          String payload = IOUtils.getResourceAsString("purchase-order2.xml", getClass());
80          internalTestSuccessfulXmlSplitter(payload.getBytes());
81      }
82  
83      private void internalTestSuccessfulXmlSplitter(Object payload) throws Exception
84      {
85          Mock session = MuleTestUtils.getMockSession();
86          session.matchAndReturn("getService", getTestService());
87  
88          MuleMessage message = new DefaultMuleMessage(payload);
89  
90          assertTrue(xmlSplitter.isMatch(message));
91          final RoundRobinXmlSplitterTestCase.ItemNodeConstraint itemNodeConstraint = new RoundRobinXmlSplitterTestCase.ItemNodeConstraint();
92          session.expect("dispatchEvent", C.args(itemNodeConstraint, C.eq(endpoint1)));
93          session.expect("dispatchEvent", C.args(itemNodeConstraint, C.eq(endpoint2)));
94          session.expect("dispatchEvent", C.args(itemNodeConstraint, C.eq(endpoint3)));
95          session.expect("dispatchEvent", C.args(itemNodeConstraint, C.eq(endpoint1)));
96          xmlSplitter.route(message, (MuleSession)session.proxy(), false);
97          session.verify();
98  
99          message = new DefaultMuleMessage(payload);
100 
101         session.expectAndReturn("sendEvent", C.args(itemNodeConstraint, C.eq(endpoint1)), message);
102         session.expectAndReturn("sendEvent", C.args(itemNodeConstraint, C.eq(endpoint2)), message);
103         session.expectAndReturn("sendEvent", C.args(itemNodeConstraint, C.eq(endpoint3)), message);
104         session.expectAndReturn("sendEvent", C.args(itemNodeConstraint, C.eq(endpoint1)), message);
105         MuleMessage result = xmlSplitter.route(message, (MuleSession)session.proxy(), true);
106         assertNotNull(result);
107         assertEquals(message, result);
108         session.verify();
109     }
110 
111     public void testXsdNotFoundThrowsException() throws Exception
112     {
113         final String invalidSchemaLocation = "non-existent.xsd";
114         Mock session = MuleTestUtils.getMockSession();
115         session.matchAndReturn("getService", getTestService());
116 
117         RoundRobinXmlSplitter splitter = new RoundRobinXmlSplitter();
118         splitter.setValidateSchema(true);
119         splitter.setExternalSchemaLocation(invalidSchemaLocation);
120 
121         String payload = IOUtils.getResourceAsString("purchase-order.xml", getClass());
122 
123         MuleMessage message = new DefaultMuleMessage(payload);
124 
125         assertTrue(splitter.isMatch(message));
126         try
127         {
128             splitter.route(message, (MuleSession)session.proxy(), false);
129             fail("Should have thrown an exception, because XSD is not found.");
130         }
131         catch (IllegalArgumentException iaex)
132         {
133             assertTrue("Wrong exception?", iaex.getMessage().indexOf(
134                 "Couldn't find schema at " + invalidSchemaLocation) != -1);
135         }
136         session.verify();
137     }
138 
139     public void testUnsupportedTypePayloadIsIgnored() throws Exception
140     {
141         Exception unsupportedPayload = new Exception();
142 
143         Mock session = MuleTestUtils.getMockSession();
144         session.matchAndReturn("getService", getTestService());
145 
146         MuleMessage message = new DefaultMuleMessage(unsupportedPayload);
147 
148         assertTrue(xmlSplitter.isMatch(message));
149         xmlSplitter.route(message, (MuleSession)session.proxy(), false);
150         session.verify();
151 
152         message = new DefaultMuleMessage(unsupportedPayload);
153 
154         MuleMessage result = xmlSplitter.route(message, (MuleSession)session.proxy(), true);
155         assertNull(result);
156         session.verify();
157     }
158 
159     public void testInvalidXmlPayloadThrowsException() throws Exception
160     {
161         Mock session = MuleTestUtils.getMockSession();
162         session.matchAndReturn("getService", getTestService());
163 
164         RoundRobinXmlSplitter splitter = new RoundRobinXmlSplitter();
165 
166         MuleMessage message = new DefaultMuleMessage("This is not XML.");
167 
168         try
169         {
170             splitter.route(message, (MuleSession)session.proxy(), false);
171             fail("No exception thrown.");
172         }
173         catch (IllegalArgumentException iaex)
174         {
175             assertTrue("Wrong exception message.", iaex.getMessage().startsWith(
176                 "Failed to initialise the payload: "));
177         }
178 
179     }
180 
181     private class ItemNodeConstraint implements Constraint
182     {
183         public boolean eval(Object o)
184         {
185             final MuleMessage message = (MuleMessage)o;
186             final Object payload = message.getPayload();
187             assertTrue("Wrong class type for node.", payload instanceof Document);
188 
189             Document node = (Document)payload;
190 
191             final String partNumber = node.getRootElement().attributeValue("partNum");
192 
193             return "872-AA".equals(partNumber) || "926-AA".equals(partNumber) || "126-AA".equals(partNumber)
194                    || "226-AA".equals(partNumber);
195         }
196     }
197 }