View Javadoc

1   /*
2    * $Id: SpringEventsTestCase.java 19191 2010-08-25 21:05:23Z 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.module.spring.events;
12  
13  import org.mule.api.MuleEventContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.module.client.MuleClient;
17  import org.mule.tck.FunctionalTestCase;
18  import org.mule.tck.functional.EventCallback;
19  import org.mule.transformer.AbstractMessageTransformer;
20  import org.mule.util.ExceptionUtils;
21  import org.mule.util.concurrent.Latch;
22  
23  import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
24  import edu.emory.mathcs.backport.java.util.concurrent.Executors;
25  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
26  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
27  import org.springframework.context.ApplicationContext;
28  import org.springframework.context.ApplicationEvent;
29  import org.springframework.context.event.ContextRefreshedEvent;
30  import org.springframework.context.support.AbstractApplicationContext;
31  
32  public class SpringEventsTestCase extends FunctionalTestCase
33  {
34      protected static final int DEFAULT_LATCH_TIMEOUT = 10000;
35  
36      private static final int NUMBER_OF_MESSAGES = 10;
37      volatile AtomicInteger eventCounter1;
38      volatile AtomicInteger eventCounter2;
39  
40      @Override
41      protected void doSetUp() throws Exception
42      {
43          super.doSetUp();
44          eventCounter1 = new AtomicInteger(0);
45          eventCounter2 = new AtomicInteger(0);
46      }
47  
48      @Override
49      protected String getConfigResources()
50      {
51          return "mule-events-app-context.xml";
52      }
53  
54      public void testManagerIsInstanciated() throws Exception
55      {
56          assertTrue(muleContext.isInitialised());
57          assertTrue(muleContext.isStarted());
58          assertNotNull(muleContext.getRegistry().lookupObject(
59              AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME));
60      }
61  
62      public void testRemovingListeners() throws Exception
63      {
64          TestSubscriptionEventBean subscriptionBean = (TestSubscriptionEventBean) muleContext.getRegistry()
65              .lookupObject("testSubscribingEventBean1");
66          assertNotNull(subscriptionBean);
67          MuleEventMulticaster multicaster = (MuleEventMulticaster) muleContext.getRegistry().lookupObject(
68              AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME);
69          assertNotNull(multicaster);
70  
71          Latch whenFinished = new Latch();
72          subscriptionBean.setEventCallback(new CountingEventCallback(eventCounter1, 1, whenFinished));
73  
74          multicaster.removeApplicationListener(subscriptionBean);
75          MuleClient client = new MuleClient(muleContext);
76          client.send("vm://event.multicaster", "Test Spring MuleEvent", null);
77  
78          assertEquals(0, eventCounter1.get());
79  
80          multicaster.addApplicationListener(subscriptionBean);
81          client.send("vm://event.multicaster", "Test Spring MuleEvent", null);
82  
83          assertTrue(whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
84          assertEquals(1, eventCounter1.get());
85          eventCounter1.set(0);
86  
87          multicaster.removeAllListeners();
88          client.send("vm://event.multicaster", "Test Spring MuleEvent", null);
89  
90          assertEquals(0, eventCounter1.get());
91          multicaster.addApplicationListener(subscriptionBean);
92          // context.refresh();
93          subscriptionBean.setEventCallback(null);
94      }
95  
96      public void testReceivingANonSubscriptionMuleEvent() throws Exception
97      {
98          TestMuleEventBean bean = (TestMuleEventBean) muleContext.getRegistry().lookupObject(
99              "testNonSubscribingMuleEventBean");
100         assertNotNull(bean);
101 
102         // register a callback
103         Latch whenFinished = new Latch();
104         bean.setEventCallback(new CountingEventCallback(eventCounter1, 1, whenFinished));
105 
106         MuleClient client = new MuleClient(muleContext);
107         client.send("vm://event.multicaster", "Test Spring MuleEvent", null);
108 
109         whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
110         assertEquals(1, eventCounter1.get());
111     }
112 
113     public void testReceivingASpringEvent() throws Exception
114     {
115         TestApplicationEventBean bean = (TestApplicationEventBean) muleContext.getRegistry().lookupObject(
116             "testEventSpringBean");
117         assertNotNull(bean);
118 
119         final Latch whenFinished = new Latch();
120         EventCallback callback = new EventCallback()
121         {
122             public void eventReceived(MuleEventContext context, Object o) throws Exception
123             {
124                 assertNull(context);
125                 if (o instanceof TestApplicationEvent)
126                 {
127                     if (eventCounter1.incrementAndGet() == 1)
128                     {
129                         whenFinished.countDown();
130                     }
131                 }
132             }
133         };
134 
135         bean.setEventCallback(callback);
136 
137         ApplicationContext context = ((MuleEventMulticaster) muleContext.getRegistry().lookupObject(
138             "applicationEventMulticaster")).applicationContext;
139         context.publishEvent(new TestApplicationEvent(context));
140 
141         whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
142         assertEquals(1, eventCounter1.get());
143     }
144 
145     public void testReceivingAllEvents() throws Exception
146     {
147         TestAllEventBean bean = (TestAllEventBean) muleContext.getRegistry().lookupObject("testAllEventBean");
148         assertNotNull(bean);
149 
150         Latch whenFinished = new Latch();
151         bean.setEventCallback(new CountingEventCallback(eventCounter1, 2, whenFinished));
152 
153         MuleClient client = new MuleClient(muleContext);
154         client.send("vm://event.multicaster", "Test Spring MuleEvent", null);
155         ApplicationContext context = ((MuleEventMulticaster) muleContext.getRegistry().lookupObject(
156             "applicationEventMulticaster")).applicationContext;
157         context.publishEvent(new TestApplicationEvent(context));
158 
159         whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
160         assertEquals(2, eventCounter1.get());
161     }
162 
163     public void testReceivingASubscriptionEvent() throws Exception
164     {
165         TestSubscriptionEventBean subscriptionBean = (TestSubscriptionEventBean) muleContext.getRegistry()
166             .lookupObject("testSubscribingEventBean1");
167         assertNotNull(subscriptionBean);
168 
169         Latch whenFinished = new Latch();
170         subscriptionBean.setEventCallback(new CountingEventCallback(eventCounter1, 1, whenFinished));
171 
172         MuleClient client = new MuleClient(muleContext);
173         client.send("vm://event.multicaster", "Test Spring MuleEvent", null);
174 
175         whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
176         assertEquals(1, eventCounter1.get());
177     }
178 
179     public void testReceiveAndPublishEvent() throws Exception
180     {
181         TestSubscriptionEventBean bean1 = (TestSubscriptionEventBean) muleContext.getRegistry().lookupObject(
182             "testSubscribingEventBean1");
183         assertNotNull(bean1);
184 
185         final Latch whenFinished1 = new Latch();
186         EventCallback callback = new EventCallback()
187         {
188             public void eventReceived(MuleEventContext context, Object o) throws Exception
189             {
190                 MuleApplicationEvent returnEvent = new MuleApplicationEvent("MuleEvent from a spring bean",
191                     "vm://testBean2");
192                 MuleApplicationEvent e = (MuleApplicationEvent) o;
193                 e.getApplicationContext().publishEvent(returnEvent);
194                 if (eventCounter1.incrementAndGet() == NUMBER_OF_MESSAGES)
195                 {
196                     whenFinished1.countDown();
197                 }
198             }
199         };
200         bean1.setEventCallback(callback);
201 
202         TestSubscriptionEventBean bean2 = (TestSubscriptionEventBean) muleContext.getRegistry().lookupObject(
203             "testSubscribingEventBean2");
204         assertNotNull(bean2);
205 
206         Latch whenFinished2 = new Latch();
207         bean2.setEventCallback(new CountingEventCallback(eventCounter2, NUMBER_OF_MESSAGES, whenFinished2));
208 
209         // send asynchronously
210         this.doSend("vm://event.multicaster", "Test Spring MuleEvent", NUMBER_OF_MESSAGES);
211 
212         whenFinished1.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
213         whenFinished2.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
214         assertEquals(NUMBER_OF_MESSAGES, eventCounter1.get());
215         assertEquals(NUMBER_OF_MESSAGES, eventCounter2.get());
216     }
217 
218     public void testPublishOnly() throws Exception
219     {
220         final MuleApplicationEvent event = new MuleApplicationEvent("MuleEvent from a spring bean",
221             "vm://testBean2");
222 
223         TestSubscriptionEventBean bean2 = (TestSubscriptionEventBean) muleContext.getRegistry().lookupObject(
224             "testSubscribingEventBean2");
225         assertNotNull(bean2);
226 
227         Latch whenFinished = new Latch();
228         bean2.setEventCallback(new CountingEventCallback(eventCounter1, NUMBER_OF_MESSAGES, whenFinished));
229 
230         // publish asynchronously
231         this.doPublish(event, NUMBER_OF_MESSAGES);
232 
233         whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
234         assertEquals(NUMBER_OF_MESSAGES, eventCounter1.get());
235     }
236 
237     public void testPublishWithEventAwareTransformer() throws Exception
238     {
239         CountDownLatch transformerLatch = new CountDownLatch(1);
240 
241         TestEventAwareTransformer trans = new TestEventAwareTransformer();
242         trans.setLatch(transformerLatch);
243         muleContext.getRegistry().registerTransformer(trans);
244 
245         MuleApplicationEvent event = new MuleApplicationEvent("MuleEvent from a spring bean",
246             "vm://testBean2?transformers=dummyTransformer");
247 
248         TestSubscriptionEventBean bean2 = (TestSubscriptionEventBean) muleContext.getRegistry().lookupObject(
249             "testSubscribingEventBean2");
250         assertNotNull(bean2);
251 
252         Latch whenFinished = new Latch();
253         bean2.setEventCallback(new CountingEventCallback(eventCounter1, 1, whenFinished));
254 
255         // publish asynchronously
256         this.doPublish(event, 1);
257 
258         whenFinished.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
259         assertTrue(transformerLatch.await(DEFAULT_LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
260         assertEquals(1, eventCounter1.get());
261     }
262 
263     // asynchronously publish the given event to the ApplicationContext for 'count' number of times
264     protected void doPublish(final ApplicationEvent event, final int count)
265     {
266         Runnable publisher = new Runnable()
267         {
268             public void run()
269             {
270                 for (int i = 0; i < count; i++)
271                 {
272                     ApplicationContext context = null;
273                     try
274                     {
275                         context = ((MuleEventMulticaster) muleContext.getRegistry().lookupObject(
276                             "applicationEventMulticaster")).applicationContext;
277                         context.publishEvent(event);
278                     }
279                     catch (IllegalArgumentException e)
280                     {
281                         // TODO Auto-generated catch block
282                         e.printStackTrace();
283                     }
284                     catch (SecurityException e)
285                     {
286                         // TODO Auto-generated catch block
287                         e.printStackTrace();
288                     }
289                 }
290             }
291         };
292 
293         Executors.newSingleThreadExecutor().execute(publisher);
294     }
295 
296     // asynchronously send the payload to the given Mule URL for 'count' number of times
297     protected void doSend(final String url, final Object payload, final int count)
298     {
299         Runnable sender = new Runnable()
300         {
301             public void run()
302             {
303                 try
304                 {
305                     MuleClient client = new MuleClient(muleContext);
306                     for (int i = 0; i < count; i++)
307                     {
308                         client.send(url, payload, null);
309                     }
310                 }
311                 catch (MuleException ex)
312                 {
313                     fail(ExceptionUtils.getStackTrace(ex));
314                 }
315             }
316         };
317 
318         // execute in background
319         Executors.newSingleThreadExecutor().execute(sender);
320     }
321 
322     /*
323      * This callback counts how many times an MuleEvent was received. If a maximum
324      * number has been reached, the given CountDownLatch is counted down. When
325      * passing in a Latch (CountDownLatch(1)) this acts just like a sempahore for the
326      * caller.
327      */
328     public static class CountingEventCallback implements EventCallback
329     {
330         private final AtomicInteger counter;
331         private final int maxCount;
332         private final CountDownLatch finished;
333 
334         public CountingEventCallback(AtomicInteger counter, int maxCount, CountDownLatch whenFinished)
335         {
336             super();
337             this.counter = counter;
338             this.maxCount = maxCount;
339             this.finished = whenFinished;
340         }
341 
342         public void eventReceived(MuleEventContext context, Object o) throws Exception
343         {
344             // apparently beans get an extra ContextRefreshedEvent during
345             // startup;
346             // this messes up our event counts.
347             if (!(o instanceof ContextRefreshedEvent))
348             {
349                 if (counter.incrementAndGet() == maxCount && finished != null)
350                 {
351                     finished.countDown();
352                 }
353             }
354         }
355     }
356 
357     /*
358      * A simple Transformer that counts down a Latch to indicate that it has been
359      * called.
360      */
361     public static class TestEventAwareTransformer extends AbstractMessageTransformer
362     {
363         private CountDownLatch latch;
364 
365         public TestEventAwareTransformer()
366         {
367             this.setName("dummyTransformer");
368         }
369 
370         @Override
371         public Object clone() throws CloneNotSupportedException
372         {
373             TestEventAwareTransformer clone = (TestEventAwareTransformer) super.clone();
374             // we MUST share the latch for this test since we obviously want to
375             // wait
376             // for it.
377             clone.setLatch(latch);
378             return clone;
379         }
380 
381         public CountDownLatch getLatch()
382         {
383             return latch;
384         }
385 
386         public void setLatch(CountDownLatch latch)
387         {
388             this.latch = latch;
389         }
390 
391         @Override
392         public Object transformMessage(MuleMessage message, String outputEncoding)
393         {
394             assertNotNull(message);
395 
396             if (latch != null)
397             {
398                 latch.countDown();
399             }
400 
401             return message;
402         }
403     }
404 
405     /*
406      * A simple custom ApplicationEvent for sending
407      */
408     public static class TestApplicationEvent extends ApplicationEvent
409     {
410         private static final long serialVersionUID = 1L;
411 
412         public TestApplicationEvent(Object source)
413         {
414             super(source);
415         }
416     }
417 
418 }