View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.processor.chain;
8   
9   import org.mule.DefaultMuleEvent;
10  import org.mule.DefaultMuleMessage;
11  import org.mule.api.MuleEvent;
12  import org.mule.api.MuleException;
13  import org.mule.api.lifecycle.InitialisationException;
14  import org.mule.api.lifecycle.Lifecycle;
15  import org.mule.api.processor.InterceptingMessageProcessor;
16  import org.mule.api.processor.MessageProcessor;
17  import org.mule.api.processor.MessageProcessorBuilder;
18  import org.mule.api.processor.MessageProcessorChain;
19  import org.mule.processor.AbstractInterceptingMessageProcessor;
20  import org.mule.tck.junit4.AbstractMuleContextTestCase;
21  import org.mule.transformer.simple.StringAppendTransformer;
22  import org.mule.util.ObjectUtils;
23  
24  import org.junit.Test;
25  
26  import static org.junit.Assert.assertEquals;
27  import static org.junit.Assert.assertFalse;
28  import static org.junit.Assert.assertNotSame;
29  import static org.junit.Assert.assertNull;
30  import static org.junit.Assert.assertTrue;
31  
32  public class DefaultMessageProcessorChainTestCase extends AbstractMuleContextTestCase
33  {
34  
35      @Test
36      public void testMPChain() throws MuleException, Exception
37      {
38          DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
39          builder.chain(new AppendingMP("1"), new AppendingMP("2"), new AppendingMP("3"));
40          assertEquals("0123", builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
41      }
42  
43      @Test
44      public void testMPChainWithNullReturn() throws MuleException, Exception
45      {
46          DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
47  
48          AppendingMP mp1 = new AppendingMP("1");
49          AppendingMP mp2 = new AppendingMP("2");
50          ReturnNullMP nullmp = new ReturnNullMP();
51          AppendingMP mp3 = new AppendingMP("3");
52  
53          builder.chain(mp1, mp2, nullmp, mp3);
54          assertEquals("0123", builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
55  
56          assertNotSame(mp1.event, mp1.resultEvent);
57          assertEquals(mp1.resultEvent, mp2.event);
58          
59          assertNotSame(mp2.event, mp2.resultEvent);
60          assertEquals(mp2.resultEvent, nullmp.event);
61  
62          assertNotSame(mp3.event, mp3.resultEvent);
63  
64          assertNotSame(nullmp.event, mp3.event);
65          assertEquals(mp3.event.getMessageAsString(), "012");
66  
67      }
68  
69      @Test
70      public void testMPChainWithNullReturnAtEnd() throws MuleException, Exception
71      {
72          DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
73          builder.chain(new AppendingMP("1"), new AppendingMP("2"), new AppendingMP("3"), new ReturnNullMP());
74          assertNull(builder.build().process(getTestEventUsingFlow("0")));
75      }
76  
77      @Test
78      public void testMPChainWithBuilder() throws MuleException, Exception
79      {
80          DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
81          builder.chain(new AppendingMP("1"));
82          builder.chain(new MessageProcessorBuilder()
83          {
84              public MessageProcessor build()
85              {
86                  return new AppendingMP("2");
87              }
88          });
89          builder.chain(new AppendingMP("3"));
90          assertEquals("0123", builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
91      }
92  
93      @Test
94      public void testInterceptingMPChain() throws MuleException, Exception
95      {
96          DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
97          builder.chain(new AppendingInterceptingMP("1"), new AppendingInterceptingMP("2"),
98              new AppendingInterceptingMP("3"));
99          assertEquals("0before1before2before3after3after2after1",
100             builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
101     }
102 
103     @Test
104     public void testInterceptingMPChainWithNullReturn() throws MuleException, Exception
105     {
106         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
107         
108         AppendingInterceptingMP lastMP = new AppendingInterceptingMP("3");
109         
110         builder.chain(new AppendingInterceptingMP("1"), new AppendingInterceptingMP("2"),
111             new ReturnNullInterceptongMP(), lastMP);
112         assertNull(builder.build().process(getTestEventUsingFlow("0")));
113         assertFalse(lastMP.invoked);
114     }
115 
116     @Test
117     public void testMixedMPChain() throws MuleException, Exception
118     {
119         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
120         builder.chain(new AppendingInterceptingMP("1"), new AppendingMP("2"), new AppendingMP("3"),
121             new AppendingInterceptingMP("4"), new AppendingMP("5"));
122         assertEquals("0before123before45after4after1", builder.build()
123             .process(getTestEventUsingFlow("0"))
124             .getMessageAsString());
125     }
126 
127     @Test
128     // Whenever there is a IMP that returns null the final result is null
129     public void testMixedMPChainWithNullReturn1() throws MuleException, Exception
130     {
131         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
132         builder.chain(new AppendingInterceptingMP("1"), new ReturnNullInterceptongMP(), new AppendingMP("2"),
133             new AppendingMP("3"), new AppendingInterceptingMP("4"), new AppendingMP("5"));
134         assertNull(builder.build().process(getTestEventUsingFlow("0")));
135     }
136 
137     @Test
138     // Whenever there is a IMP that returns null the final result is null
139     public void testMixedMPChainWithNullReturn2() throws MuleException, Exception
140     {
141         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
142         builder.chain(new AppendingInterceptingMP("1"), new AppendingMP("2"), new ReturnNullInterceptongMP(),
143             new AppendingMP("3"), new AppendingInterceptingMP("4"), new AppendingMP("5"));
144         assertNull(builder.build().process(getTestEventUsingFlow("0")));
145     }
146 
147     @Test
148     // A simple MP that returns null does not affect flow as long as it's not at the
149     // end
150     public void testMixedMPChainWithNullReturn3() throws MuleException, Exception
151     {
152         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
153         builder.chain(new AppendingInterceptingMP("1"), new ReturnNullMP(), new AppendingMP("2"),
154             new AppendingMP("3"), new AppendingInterceptingMP("4"), new AppendingMP("5"));
155         assertEquals("0before123before45after4after1", builder.build()
156             .process(getTestEventUsingFlow("0"))
157             .getMessageAsString());
158     }
159 
160     @Test
161     // A simple MP that returns null does not affect flow as long as it's not at the
162     // end
163     public void testMixedMPChainWithNullReturn4() throws MuleException, Exception
164     {
165         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
166         builder.chain(new AppendingInterceptingMP("1"), new AppendingMP("2"), new ReturnNullMP(),
167             new AppendingMP("3"), new AppendingInterceptingMP("4"), new AppendingMP("5"));
168         assertEquals("0before123before45after4after1", builder.build()
169             .process(getTestEventUsingFlow("0"))
170             .getMessageAsString());
171     }
172 
173     @Test
174     // A simple MP that returns null does not affect flow as long as it's not at the
175     // end
176     public void testMixedMPChainWithNullReturn5() throws MuleException, Exception
177     {
178         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
179         builder.chain(new AppendingInterceptingMP("1"), new AppendingMP("2"), new AppendingMP("3"),
180             new ReturnNullMP(), new AppendingInterceptingMP("4"), new AppendingMP("5"));
181         assertEquals("0before123before45after4after1", builder.build()
182             .process(getTestEventUsingFlow("0"))
183             .getMessageAsString());
184     }
185 
186     @Test
187     // A simple MP at the end of a single level chain causes chain to return null
188     public void testMixedMPChainWithNullReturnAtEnd() throws MuleException, Exception
189     {
190         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
191         builder.chain(new AppendingInterceptingMP("1"), new AppendingMP("2"), new AppendingMP("3"),
192             new AppendingInterceptingMP("4"), new AppendingMP("5"), new ReturnNullMP());
193         assertNull(builder.build().process(getTestEventUsingFlow("0")));
194     }
195 
196     @Test
197     public void testNestedMPChain() throws MuleException, Exception
198     {
199         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
200         builder.chain(new AppendingMP("1"),
201             new DefaultMessageProcessorChainBuilder().chain(new AppendingMP("a"), new AppendingMP("b"))
202                 .build(), new AppendingMP("2"));
203         assertEquals("01ab2", builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
204     }
205 
206     @Test
207     public void testNestedMPChainWithNullReturn() throws MuleException, Exception
208     {
209         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
210         builder.chain(
211             new AppendingMP("1"),
212             new DefaultMessageProcessorChainBuilder().chain(new AppendingMP("a"), new ReturnNullMP(),
213                 new AppendingMP("b")).build(), new ReturnNullMP(), new AppendingMP("2"));
214         assertEquals("01ab2", builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
215     }
216 
217     @Test
218     public void testNestedMPChainWithNullReturnAtEndOfNestedChain() throws MuleException, Exception
219     {
220         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
221         builder.chain(
222             new AppendingMP("1"),
223             new DefaultMessageProcessorChainBuilder().chain(new AppendingMP("a"), new AppendingMP("b"),
224                 new ReturnNullMP()).build(), new AppendingMP("2"));
225         assertNull(builder.build().process(getTestEventUsingFlow("0")));
226     }
227 
228     @Test
229     public void testNestedMPChainWithNullReturnAtEndOfNestedChainWithNonInterceptingWrapper() throws MuleException, Exception
230     {
231         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
232         final MessageProcessor nested = new DefaultMessageProcessorChainBuilder().chain(new AppendingMP("a"),
233             new AppendingMP("b"), new ReturnNullMP()).build();
234         builder.chain(new AppendingMP("1"), new MessageProcessor()
235         {
236             public MuleEvent process(MuleEvent event) throws MuleException
237             {
238                 return nested.process(event);
239             }
240         }, new AppendingMP("2"));
241         assertEquals("012", builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
242     }
243 
244     @Test
245     public void testNestedInterceptingMPChain() throws MuleException, Exception
246     {
247         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
248         builder.chain(
249             new AppendingInterceptingMP("1"),
250             new DefaultMessageProcessorChainBuilder().chain(new AppendingInterceptingMP("a"),
251                 new AppendingInterceptingMP("b")).build(), new AppendingInterceptingMP("2"));
252         assertEquals("0before1beforeabeforebafterbafterabefore2after2after1",
253             builder.build().process(getTestEventUsingFlow("0")).getMessageAsString());
254     }
255 
256     @Test
257     public void testNestedInterceptingMPChainWithNullReturn() throws MuleException, Exception
258     {
259         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
260         builder.chain(
261             new AppendingInterceptingMP("1"),
262             new DefaultMessageProcessorChainBuilder().chain(new AppendingInterceptingMP("a"),
263                 new ReturnNullInterceptongMP(), new AppendingInterceptingMP("b")).build(),
264             new AppendingInterceptingMP("2"));
265         assertNull(builder.build().process(getTestEventUsingFlow("0")));
266     }
267 
268     @Test
269     public void testNestedMixedMPChain() throws MuleException, Exception
270     {
271         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
272         builder.chain(
273             new AppendingMP("1"),
274             new DefaultMessageProcessorChainBuilder().chain(new AppendingInterceptingMP("a"),
275                 new AppendingMP("b")).build(), new AppendingInterceptingMP("2"));
276         assertEquals("01beforeabafterabefore2after2", builder.build()
277             .process(getTestEventUsingFlow("0"))
278             .getMessageAsString());
279     }
280 
281     @Test
282     public void testInterceptingMPChainStopFlow() throws MuleException, Exception
283     {
284         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
285         builder.chain(new AppendingInterceptingMP("1"), new AppendingInterceptingMP("2", true),
286             new AppendingInterceptingMP("3"));
287         assertEquals("0before1after1", builder.build()
288             .process(getTestEventUsingFlow("0"))
289             .getMessageAsString());
290     }
291 
292     /**
293      * Note: Stopping the flow of a nested chain causes the nested chain to return early, but does not stop
294      * the flow of the parent chain.
295      */
296     @Test
297     public void testNestedInterceptingMPChainStopFlow() throws MuleException, Exception
298     {
299         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
300         builder.chain(
301             new AppendingInterceptingMP("1"),
302             new DefaultMessageProcessorChainBuilder().chain(new AppendingInterceptingMP("a", true),
303                 new AppendingInterceptingMP("b")).build(), new AppendingInterceptingMP("3"));
304         assertEquals("0before1before3after3after1", builder.build()
305             .process(getTestEventUsingFlow("0"))
306             .getMessageAsString());
307     }
308 
309     @Test
310     public void testMPChainLifecycle() throws MuleException, Exception
311     {
312         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
313         AppendingMP mp1 = new AppendingInterceptingMP("1");
314         AppendingMP mp2 = new AppendingInterceptingMP("2");
315         MessageProcessor chain = builder.chain(mp1, mp2).build();
316         ((Lifecycle) chain).initialise();
317         ((Lifecycle) chain).start();
318         ((Lifecycle) chain).stop();
319         ((Lifecycle) chain).dispose();
320         assertLifecycle(mp1);
321         assertLifecycle(mp2);
322     }
323 
324     @Test
325     public void testNestedMPChainLifecycle() throws MuleException, Exception
326     {
327         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
328         DefaultMessageProcessorChainBuilder nestedBuilder = new DefaultMessageProcessorChainBuilder();
329         AppendingMP mp1 = new AppendingInterceptingMP("1");
330         AppendingMP mp2 = new AppendingInterceptingMP("2");
331         AppendingMP mpa = new AppendingInterceptingMP("a");
332         AppendingMP mpb = new AppendingInterceptingMP("b");
333         MessageProcessor chain = builder.chain(mp1, nestedBuilder.chain(mpa, mpb).build(), mp2).build();
334         ((Lifecycle) chain).initialise();
335         ((Lifecycle) chain).start();
336         ((Lifecycle) chain).stop();
337         ((Lifecycle) chain).dispose();
338         assertLifecycle(mp1);
339         assertLifecycle(mp2);
340         assertLifecycle(mpa);
341         assertLifecycle(mpb);
342     }
343 
344     @Test
345     public void testNoneIntercepting() throws Exception
346     {
347         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
348         builder.chain(new TestNonIntercepting(), new TestNonIntercepting(), new TestNonIntercepting());
349         MuleEvent restul = builder.build().process(getTestEventUsingFlow(""));
350         assertEquals("MessageProcessorMessageProcessorMessageProcessor", restul.getMessageAsString());
351     }
352 
353     @Test
354     public void testAllIntercepting() throws Exception
355     {
356         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
357         builder.chain(new TestIntercepting(), new TestIntercepting(), new TestIntercepting());
358         MuleEvent restul = builder.build().process(getTestEventUsingFlow(""));
359         assertEquals("InterceptingMessageProcessorInterceptingMessageProcessorInterceptingMessageProcessor",
360             restul.getMessageAsString());
361     }
362 
363     @Test
364     public void testMix() throws Exception
365     {
366         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
367         builder.chain(new TestIntercepting(), new TestNonIntercepting(), new TestNonIntercepting(),
368             new TestIntercepting(), new TestNonIntercepting(), new TestNonIntercepting());
369         MuleEvent restul = builder.build().process(getTestEventUsingFlow(""));
370         assertEquals(
371             "InterceptingMessageProcessorMessageProcessorMessageProcessorInterceptingMessageProcessorMessageProcessorMessageProcessor",
372             restul.getMessageAsString());
373     }
374 
375     @Test
376     public void testMixStaticFactoryt() throws Exception
377     {
378         MessageProcessorChain chain = DefaultMessageProcessorChain.from(new TestIntercepting(),
379             new TestNonIntercepting(), new TestNonIntercepting(), new TestIntercepting(),
380             new TestNonIntercepting(), new TestNonIntercepting());
381         MuleEvent restul = chain.process(getTestEventUsingFlow(""));
382         assertEquals(
383             "InterceptingMessageProcessorMessageProcessorMessageProcessorInterceptingMessageProcessorMessageProcessorMessageProcessor",
384             restul.getMessageAsString());
385     }
386 
387     @Test
388     public void testMix2() throws Exception
389     {
390         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
391         builder.chain(new TestNonIntercepting(), new TestIntercepting(), new TestNonIntercepting(),
392             new TestNonIntercepting(), new TestNonIntercepting(), new TestIntercepting());
393         MuleEvent restul = builder.build().process(getTestEventUsingFlow(""));
394         assertEquals(
395             "MessageProcessorInterceptingMessageProcessorMessageProcessorMessageProcessorMessageProcessorInterceptingMessageProcessor",
396             restul.getMessageAsString());
397     }
398 
399     @Test
400     public void testMix2StaticFactory() throws Exception
401     {
402         MessageProcessorChain chain = DefaultMessageProcessorChain.from(new TestNonIntercepting(),
403             new TestIntercepting(), new TestNonIntercepting(), new TestNonIntercepting(),
404             new TestNonIntercepting(), new TestIntercepting());
405         MuleEvent restul = chain.process(getTestEventUsingFlow(""));
406         assertEquals(
407             "MessageProcessorInterceptingMessageProcessorMessageProcessorMessageProcessorMessageProcessorInterceptingMessageProcessor",
408             restul.getMessageAsString());
409     }
410 
411     static class TestNonIntercepting implements MessageProcessor
412     {
413         public MuleEvent process(MuleEvent event) throws MuleException
414         {
415             return new StringAppendTransformer("MessageProcessor").process(event);
416         }
417     }
418 
419     static class TestIntercepting extends AbstractInterceptingMessageProcessor
420     {
421         public MuleEvent process(MuleEvent event) throws MuleException
422         {
423             return processNext(new StringAppendTransformer("InterceptingMessageProcessor").process(event));
424         }
425     }
426 
427     private void assertLifecycle(AppendingMP mp)
428     {
429         assertTrue(mp.initialised);
430         assertTrue(mp.started);
431         assertTrue(mp.stopped);
432         assertTrue(mp.disposed);
433     }
434 
435     private static class AppendingMP implements MessageProcessor, Lifecycle
436     {
437         String appendString;
438         boolean initialised;
439         boolean started;
440         boolean stopped;
441         boolean disposed;
442         MuleEvent event;
443         MuleEvent resultEvent;
444 
445         public AppendingMP(String append)
446         {
447             this.appendString = append;
448         }
449 
450         public MuleEvent process(MuleEvent event) throws MuleException
451         {
452             this.event = event;
453             MuleEvent result = new DefaultMuleEvent(new DefaultMuleMessage(event.getMessageAsString() + appendString,
454                 muleContext), event);
455             this.resultEvent = result;
456             return result;
457         }
458 
459         public void initialise() throws InitialisationException
460         {
461             initialised = true;
462         }
463 
464         public void start() throws MuleException
465         {
466             started = true;
467         }
468 
469         public void stop() throws MuleException
470         {
471             stopped = true;
472         }
473 
474         public void dispose()
475         {
476             disposed = true;
477         }
478 
479         @Override
480         public String toString()
481         {
482             return ObjectUtils.toString(this);
483         }
484     }
485 
486     private static class AppendingInterceptingMP extends AppendingMP implements InterceptingMessageProcessor
487     {
488         private boolean stopProcessing;
489         private MessageProcessor next;
490         boolean invoked = false;
491 
492         public AppendingInterceptingMP(String append)
493         {
494             this(append, false);
495         }
496 
497         public AppendingInterceptingMP(String append, boolean stopProcessing)
498         {
499             super(append);
500             this.stopProcessing = stopProcessing;
501         }
502 
503         public MuleEvent process(MuleEvent event) throws MuleException
504         {
505             invoked = true;
506             this.event = event;
507 
508             if (stopProcessing)
509             {
510                 return event;
511             }
512 
513             MuleEvent intermediateEvent = new DefaultMuleEvent(new DefaultMuleMessage(
514                 event.getMessageAsString() + "before" + appendString, muleContext), event);
515             if (next != null)
516             {
517                 intermediateEvent = next.process(intermediateEvent);
518             }
519             if (intermediateEvent != null)
520             {
521                 return new DefaultMuleEvent(new DefaultMuleMessage(intermediateEvent.getMessageAsString()
522                                                                    + "after" + appendString, muleContext),
523                     intermediateEvent);
524             }
525             else
526             {
527                 return null;
528             }
529         }
530 
531         public void setListener(MessageProcessor mp)
532         {
533             next = mp;
534         }
535 
536         @Override
537         public String toString()
538         {
539             return ObjectUtils.toString(this);
540         }
541     }
542 
543     private static class ReturnNullMP implements MessageProcessor
544     {
545         MuleEvent event;
546 
547         public MuleEvent process(MuleEvent event) throws MuleException
548         {
549             this.event = event;
550             event.getMessage().setPayload("RUBBISH");
551             return null;
552         }
553     }
554 
555     private static class ReturnNullInterceptongMP extends AbstractInterceptingMessageProcessor
556     {
557         public MuleEvent process(MuleEvent event) throws MuleException
558         {
559             return null;
560         }
561     }
562 
563 }