View Javadoc

1   /*
2    * $Id: DefaultOutboundRouterCollectionTestCase.java 19739 2010-09-27 14:28:40Z tcarlson $
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.MessageExchangePattern;
14  import org.mule.api.MessagingException;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.MuleMessage;
18  import org.mule.api.processor.MessageProcessor;
19  import org.mule.api.routing.OutboundRouterCollection;
20  import org.mule.api.service.Service;
21  import org.mule.api.transformer.Transformer;
22  import org.mule.api.transformer.TransformerException;
23  import org.mule.api.transport.OutputHandler;
24  import org.mule.component.simple.PassThroughComponent;
25  import org.mule.model.seda.SedaModel;
26  import org.mule.model.seda.SedaService;
27  import org.mule.tck.AbstractMuleTestCase;
28  import org.mule.transformer.AbstractTransformer;
29  
30  import java.io.IOException;
31  import java.io.OutputStream;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
36  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
37  
38  public class DefaultOutboundRouterCollectionTestCase extends AbstractMuleTestCase
39  {
40      public DefaultOutboundRouterCollectionTestCase()
41      {
42          setStartContext(true);
43      }
44  
45      private static int LATCH_AWAIT_TIMEOUT_MS = 1000;
46      private Service testService;
47      private MuleEvent testEvent;
48      static MuleMessage originalMessage;
49      private TestOutboundRouterCollection outboundRouter;
50  
51      @Override
52      protected void doSetUp() throws Exception
53      {
54          super.doSetUp();
55          testEvent = getTestEvent("TEST_MESSAGE", getTestInboundEndpoint(MessageExchangePattern.REQUEST_RESPONSE));
56          testService = createService();
57          outboundRouter = new TestOutboundRouterCollection();
58          testService.setOutboundMessageProcessor(outboundRouter);
59          outboundRouter.setMuleContext(muleContext);
60          muleContext.getRegistry().registerService(testService);
61      }
62  
63      protected Service createService() throws MuleException
64      {
65          SedaModel model = new SedaModel();
66          muleContext.getRegistry().registerModel(model);
67          Service service = new SedaService(muleContext);
68          service.setName("test");
69          service.setComponent(new PassThroughComponent());
70          service.setModel(model);
71          return service;
72      }
73  
74      /**
75       * If there is just one outbound router we don't need to do any copying at all
76       * regardless of if matchAll is true or not or if the router mutates the message
77       * in isMatch or not . The outbound phase already has a new message copy.
78       * @throws Exception if the test fails!
79       */
80      public void testSingleDoesNotRequireCopyRouterMatchAllFalse() throws Exception
81      {
82          getOutboundRouterCollection().setMatchAll(false);
83          getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
84          TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(1);
85  
86          testService.sendEvent(testEvent);
87  
88          assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
89              TimeUnit.MILLISECONDS));
90      }
91  
92      /**
93       * If there is just one outbound router we don't need to do any copying at all
94       * regardless of if matchAll is true or not or if the router mutates the message
95       * in isMatch or not . The outbound phase already has a new message copy.
96       * @throws Exception if the test fails!
97       */
98      public void testSingleDoesNotRequireCopyRouterMatchAllTrue() throws Exception
99      {
100 
101         MuleEvent testEvent = getTestInboundEvent("TEST_MESSAGE");
102         getOutboundRouterCollection().setMatchAll(true);
103         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
104 
105         TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(1);
106 
107         testService.sendEvent(testEvent);
108 
109         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
110             TimeUnit.MILLISECONDS));
111     }
112 
113     /**
114      * If there is just one outbound router we don't need to do any copying at all
115      * regardless of if matchAll is true or not or if the router mutates the message
116      * in isMatch or not . The outbound phase already has a new message copy.
117      * @throws Exception if the test fails!
118      */
119     public void testSingleRequiresCopyRouterMatchAllFalse() throws Exception
120     {
121         getOutboundRouterCollection().setMatchAll(false);
122         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
123 
124         TestRequiresNewMessageOutboundRouter.latch = new CountDownLatch(1);
125 
126         testService.sendEvent(testEvent);
127 
128         assertTrue(TestRequiresNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
129             TimeUnit.MILLISECONDS));
130     }
131 
132     /**
133      * If there is just one outbound router we don't need to do any copying at all
134      * regardless of if matchAll is true or not or if the router mutates the message
135      * in isMatch or not . The outbound phase already has a new message copy.
136      * @throws Exception if the test fails!
137      */
138     public void testSingleRequiresCopyRouterMatchAllTrue() throws Exception
139     {
140         getOutboundRouterCollection().setMatchAll(true);
141         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
142 
143         TestRequiresNewMessageOutboundRouter.latch = new CountDownLatch(1);
144 
145         testService.sendEvent(testEvent);
146 
147         assertTrue(TestRequiresNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
148             TimeUnit.MILLISECONDS));
149     }
150 
151     // MULTIPLE
152 
153     /**
154      * If there are multiple outbound routers but matchAll is false then we only need
155      * to copy message if the router might mutate it in isMatch, if not then no need
156      * to copy.
157      * @throws Exception if the test fails!
158      */
159     public void testMultipleDoesNotRequireCopyRouterMatchAllFalse() throws Exception
160     {
161         getOutboundRouterCollection().setMatchAll(false);
162         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
163         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
164         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
165 
166         TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(3);
167 
168         testService.sendEvent(testEvent);
169 
170         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
171             TimeUnit.MILLISECONDS));
172     }
173 
174     /**
175      * If there are multiple outbound routers and matchAll is true then we need a new
176      * message copy for all but the *last* router independent of whether the routers
177      * may mutate the message in isMatch or not. See MULE- 4352.
178      * @throws Exception if the test fails!
179      */
180     public void testMultipleDoesNotRequireCopyRouterMatchAllTrue() throws Exception
181     {
182 
183         MuleEvent testEvent = getTestInboundEvent("TEST_MESSAGE");
184         getOutboundRouterCollection().setMatchAll(true);
185         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(true));
186         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(true));
187         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
188 
189         TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(3);
190 
191         testService.sendEvent(testEvent);
192 
193         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
194             TimeUnit.MILLISECONDS));
195     }
196 
197     /**
198      * If there are multiple outbound routers and matchAll is false then we need a
199      * new message copy for all but the *last* router that may mutate the message in
200      * isMatch.
201      * @throws Exception if the test fails!
202      */
203     public void testMultipleRequiresCopyRouterMatchAllFalse() throws Exception
204     {
205         getOutboundRouterCollection().setMatchAll(false);
206         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
207         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
208         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
209 
210         TestRequiresNewMessageOutboundRouter.latch = new CountDownLatch(3);
211 
212         testService.sendEvent(testEvent);
213 
214         assertTrue(TestRequiresNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
215             TimeUnit.MILLISECONDS));
216     }
217 
218     /**
219      * If there are multiple outbound routers and matchAll is true then we need a new
220      * message copy for all but the *last* router independent of whether the routers
221      * may mutate the message in isMatch or not. See MULE- 4352.
222      * @throws Exception if the test fails!
223      */
224     public void testMultipleRequiresCopyRouterMatchAllTrue() throws Exception
225     {
226         getOutboundRouterCollection().setMatchAll(true);
227         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
228         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
229         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
230 
231         TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(3);
232 
233         testService.sendEvent(testEvent);
234 
235         assertTrue(TestRequiresNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
236             TimeUnit.MILLISECONDS));
237     }
238 
239     // MIX
240 
241     /**
242      * If matchAll is true then we need a new message copy for each and every router except the last one.
243      * @throws Exception if the test fails!
244      */
245     public void testMultipleMixMatchAllTrue() throws Exception
246     {
247         getOutboundRouterCollection().setMatchAll(true);
248         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
249         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(true));
250         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
251         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(true));
252         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
253 
254         TestRequiresNewMessageOutboundRouter.latch = new CountDownLatch(3);
255         TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(2);
256 
257         testService.sendEvent(testEvent);
258 
259         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
260             TimeUnit.MILLISECONDS));
261         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
262             TimeUnit.MILLISECONDS));
263     }
264 
265     /**
266      * If matchAll is false then we need a new message copy for each router that may
267      * mutate the message in isMatch unless it is the last router.
268      * @throws Exception if the test fails!
269      */
270     public void testMultipleMixMatchAllFalse() throws Exception
271     {
272         getOutboundRouterCollection().setMatchAll(false);
273         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
274         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
275         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
276         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(true));
277         getOutboundRouterCollection().addRoute(new TestDoesNotRequireNewMessageOutboundRouter(false));
278         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
279 
280         TestDoesNotRequireNewMessageOutboundRouter.latch = new CountDownLatch(3);
281         TestRequiresNewMessageOutboundRouter.latch = new CountDownLatch(3);
282 
283         testService.sendEvent(testEvent);
284 
285         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
286             TimeUnit.MILLISECONDS));
287         assertTrue(TestDoesNotRequireNewMessageOutboundRouter.latch.await(LATCH_AWAIT_TIMEOUT_MS,
288             TimeUnit.MILLISECONDS));
289     }
290 
291     /**
292      * If the message is a stream and message copying is required due to any of the
293      * scenarios tested above then an exception should be thrown as the stream
294      * payload cannot be copied.
295      * @throws Exception if the test fails!
296      */
297     public void testStreamPayload() throws Exception
298     {
299         getOutboundRouterCollection().setMatchAll(true);
300         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
301         getOutboundRouterCollection().addRoute(new TestRequiresNewMessageOutboundRouter(false));
302 
303         TestRequiresNewMessageOutboundRouter.latch = new CountDownLatch(2);
304 
305         testEvent.getMessage().setPayload(new OutputHandler()
306         {
307             public void write(MuleEvent event, OutputStream out) throws IOException
308             {
309                 // do nothing
310             }
311         });
312         try
313         {
314             testService.sendEvent(testEvent);
315             fail("Exception was expected");
316         }
317         catch (MessagingException e)
318         {
319             // expected 
320         }
321     }
322 
323     private OutboundRouterCollection getOutboundRouterCollection()
324     {
325         return (OutboundRouterCollection) testService.getOutboundMessageProcessor();
326     }
327     
328     private static class TestRequiresNewMessageOutboundRouter extends OutboundPassThroughRouter
329     {
330         static CountDownLatch latch;
331         private boolean expectCopy;
332 
333         public TestRequiresNewMessageOutboundRouter(boolean expectCopy)
334         {
335             this.expectCopy = expectCopy;
336             List<Transformer> transformers = new ArrayList<Transformer>();
337             transformers.add(new AbstractTransformer() 
338             {
339                 @Override
340                 public Object doTransform(Object src, String encoding) throws TransformerException
341                 {
342                     return src;
343                 }
344             });
345             setTransformers(transformers);
346         }
347 
348         @Override
349         public List<MessageProcessor> getRoutes()
350         {
351             List<MessageProcessor> list = new ArrayList<MessageProcessor>();
352             try
353             {
354                 list.add(getTestOutboundEndpoint("out", "test://out"));
355             }
356             catch (Exception e)
357             {
358                 fail(e.getMessage());
359             }
360             return list;
361         }
362 
363         @Override
364         public boolean isMatch(MuleMessage message) throws MuleException
365         {
366             if (expectCopy)
367             {
368                 assertNotSame(originalMessage, message);
369             }
370             else
371             {
372                 assertSame(originalMessage, message);
373             }
374             latch.countDown();
375             return false;
376         }
377     }
378 
379     private static class TestDoesNotRequireNewMessageOutboundRouter extends OutboundPassThroughRouter
380     {
381         static CountDownLatch latch;
382         private boolean expectCopy;
383 
384         public TestDoesNotRequireNewMessageOutboundRouter(boolean expectCopy)
385         {
386             this.expectCopy = expectCopy;
387         }
388 
389         @Override
390         public List<MessageProcessor> getRoutes()
391         {
392             List<MessageProcessor> list = new ArrayList<MessageProcessor>();
393             try
394             {
395                 list.add(getTestOutboundEndpoint("out", "test://out"));
396             }
397             catch (Exception e)
398             {
399                 fail(e.getMessage());
400             }
401             return list;
402         }
403 
404         @Override
405         public boolean isMatch(MuleMessage message) throws MuleException
406         {
407             if (expectCopy)
408             {
409                 assertNotSame(originalMessage, message);
410             }
411             else
412             {
413                 assertSame(originalMessage, message);
414 
415             }
416             latch.countDown();
417             return false;
418         }
419     }
420 
421     private static class TestOutboundRouterCollection extends DefaultOutboundRouterCollection
422     {
423         public TestOutboundRouterCollection()
424         {
425             super();
426         }
427 
428         @Override
429         public MuleEvent process(MuleEvent event) throws MessagingException
430         {
431             originalMessage = event.getMessage();
432             return super.process(event);
433         }
434     }
435 }