View Javadoc

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