View Javadoc

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