View Javadoc

1   /*
2    * $Id: ConnectorLifecycleTestCase.java 22387 2011-07-12 03:53:36Z 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.transport;
12  
13  
14  import org.mule.api.MuleException;
15  import org.mule.api.endpoint.InboundEndpoint;
16  import org.mule.api.endpoint.OutboundEndpoint;
17  import org.mule.api.lifecycle.LifecycleException;
18  import org.mule.api.service.Service;
19  import org.mule.api.source.CompositeMessageSource;
20  import org.mule.api.transport.MessageDispatcher;
21  import org.mule.api.transport.MessageRequester;
22  import org.mule.tck.junit4.AbstractMuleContextTestCase;
23  import org.mule.tck.testmodels.mule.TestConnector;
24  
25  import javax.resource.spi.work.Work;
26  import javax.resource.spi.work.WorkException;
27  
28  import junit.framework.Assert;
29  import org.junit.Test;
30  
31  import static org.junit.Assert.assertEquals;
32  import static org.junit.Assert.assertFalse;
33  import static org.junit.Assert.assertNotNull;
34  import static org.junit.Assert.assertNull;
35  import static org.junit.Assert.assertTrue;
36  import static org.junit.Assert.fail;
37  
38  /**
39   * Tests that lifecycle methods on a connector are not processed more than once. (@see MULE-3062)
40   * Also test lifecycle of a connector dispatchers, receivers, workManagers and scheduler.
41   */
42  public class ConnectorLifecycleTestCase extends AbstractMuleContextTestCase
43  {
44      private TestConnector connector;
45  
46      @Override
47      public void doSetUp() throws Exception
48      {
49          connector = new TestConnector(muleContext);
50          connector.initialise();
51      }
52  
53      @Override
54      public void doTearDown() throws Exception
55      {
56          if(!connector.isDisposed()) connector.dispose();
57          connector = null;
58      }
59  
60      /**
61       * This test ensures that the connector is only initialised once even on a
62       * direct initialisation (not through Mule).
63       *
64       * @throws Exception if things go pear-shaped
65       */
66      @Test
67      public void testDoubleInitialiseConnector() throws Exception
68      {
69          // Note: the connector was already initialized once during doSetUp()
70  
71          // Initialising the connector should leave it disconnected.
72          assertEquals(1, connector.getInitialiseCount());
73          assertEquals(0, connector.getConnectCount());
74          assertEquals(0, connector.getStartCount());
75          assertEquals(0, connector.getStopCount());
76          assertEquals(0, connector.getDisconnectCount());
77          assertEquals(0, connector.getDisposeCount());
78  
79          // Initialising the connector again should not throw an exception.
80          try
81          {
82              connector.initialise();
83              Assert.fail("Expected IllegalStateException not thrown.");
84          }
85          catch (IllegalStateException ex)
86          {
87              // ignore since expected
88          }
89      }
90  
91      /**
92       * This test ensures that the connector is only started once even on a
93       * direct restart (not through Mule).
94       *
95       * @throws Exception if things go pear-shaped
96       */
97      @Test
98      public void testDoubleStartConnector() throws Exception
99      {
100         // Starting the connector should leave it uninitialised,
101         // but connected and started.
102         connector.start();
103         assertEquals(1, connector.getInitialiseCount());
104         assertEquals(1, connector.getConnectCount());
105         assertEquals(1, connector.getStartCount());
106         assertEquals(0, connector.getStopCount());
107         assertEquals(0, connector.getDisconnectCount());
108         assertEquals(0, connector.getDisposeCount());
109 
110         // Starting the connector again
111         try
112         {
113             connector.start();
114             fail("cannot start the connector twice");
115         }
116         catch (IllegalStateException e)
117         {
118             //expected
119         }
120         assertEquals(1, connector.getInitialiseCount());
121         assertEquals(1, connector.getConnectCount());
122         assertEquals(1, connector.getStartCount());
123         assertEquals(0, connector.getStopCount());
124         assertEquals(0, connector.getDisconnectCount());
125         assertEquals(0, connector.getDisposeCount());
126     }
127 
128     /**
129      * This test ensures that the connector is only stopped once even on a
130      * direct restop (not through Mule).
131      *
132      * @throws Exception if things go pear-shaped
133      */
134     @Test
135     public void testDoubleStopConnector() throws Exception
136     {
137         // Starting the connector should leave it uninitialised,
138         // but connected and started.
139         connector.start();
140         assertEquals(1, connector.getInitialiseCount());
141         assertEquals(1, connector.getConnectCount());
142         assertEquals(1, connector.getStartCount());
143         assertEquals(0, connector.getStopCount());
144         assertEquals(0, connector.getDisconnectCount());
145         assertEquals(0, connector.getDisposeCount());
146 
147         assertTrue(connector.isStarted());
148 
149         // Stopping the connector should stop but not disconnect it.
150         connector.stop();
151         assertEquals(1, connector.getInitialiseCount());
152         assertEquals(1, connector.getConnectCount());
153         assertEquals(1, connector.getStartCount());
154         assertEquals(1, connector.getStopCount());
155         assertEquals(0, connector.getDisconnectCount());
156         assertEquals(0, connector.getDisposeCount());
157 
158 
159         try
160         {
161             connector.stop();
162             fail("cannot stop the connector twice");
163         }
164         catch (IllegalStateException e)
165         {
166             //expected
167         }
168         
169         connector.disconnect();
170         assertEquals(1, connector.getInitialiseCount());
171         assertEquals(1, connector.getConnectCount());
172         assertEquals(1, connector.getStartCount());
173         assertEquals(1, connector.getStopCount());
174         assertEquals(1, connector.getDisconnectCount());
175         assertEquals(0, connector.getDisposeCount());
176     }
177 
178     /**
179      * This test ensures that the connector is only disposed once even on a
180      * direct disposal (not through Mule).
181      *
182      * @throws Exception if things go pear-shaped
183      */
184     @Test
185     public void testDoubleDisposeConnectorStartStop() throws Exception
186     {
187         connector.start();
188         assertTrue(connector.isStarted());
189 
190         connector.stop();
191         assertFalse(connector.isStarted());
192 
193         // Disposing the connector should leave it uninitialised.
194         connector.dispose();
195         assertEquals(1, connector.getInitialiseCount());
196         assertEquals(1, connector.getConnectCount());
197         assertEquals(1, connector.getStartCount());
198         assertEquals(1, connector.getStopCount());
199         assertEquals(1, connector.getDisconnectCount());
200         assertEquals(1, connector.getDisposeCount());
201 
202         try
203         {
204             connector.dispose();
205             fail("cannot dispose the connector twice");
206         }
207         catch (IllegalStateException e)
208         {
209             //expected
210         }
211         assertEquals(1, connector.getInitialiseCount());
212         assertEquals(1, connector.getConnectCount());
213         assertEquals(1, connector.getStartCount());
214         assertEquals(1, connector.getStopCount());
215         assertEquals(1, connector.getDisconnectCount());
216         assertEquals(1, connector.getDisposeCount());
217     }
218 
219     /**
220      * This test ensures that the connector is only disposed once even on a
221      * direct disposal (not through Mule).
222      *
223      * @throws Exception if things go pear-shaped
224      */
225     @Test
226     public void testDoubleDisposeConnectorStartOnly() throws Exception
227     {
228         connector.start();
229         assertTrue(connector.isStarted());
230 
231         // Disposing the connector should leave it uninitialised.
232         connector.dispose();
233         assertEquals(1, connector.getInitialiseCount());
234         assertEquals(1, connector.getConnectCount());
235         assertEquals(1, connector.getStartCount());
236         // dispose() implicitly calls stop()
237         assertEquals(1, connector.getStopCount());
238         assertEquals(1, connector.getDisconnectCount());
239         assertEquals(1, connector.getDisposeCount());
240 
241         try
242         {
243             connector.dispose();
244             fail("cannot dispose the connector twice");
245         }
246         catch (IllegalStateException e)
247         {
248             //expected
249         }
250         assertEquals(1, connector.getInitialiseCount());
251         assertEquals(1, connector.getConnectCount());
252         assertEquals(1, connector.getStartCount());
253         // dispose() implicitly calls stop()
254         assertEquals(1, connector.getStopCount());
255         assertEquals(1, connector.getDisconnectCount());
256         assertEquals(1, connector.getDisposeCount());
257     }
258 
259     /**
260      * This test ensures that the connector is only disposed once even on a
261      * direct disposal (not through Mule).
262      *
263      * @throws Exception if things go pear-shaped
264      */
265     @Test
266     public void testDoubleDisposeConnector() throws Exception
267     {
268         // Disposing the connector should leave it uninitialised.
269         connector.dispose();
270         assertEquals(1, connector.getInitialiseCount());
271         assertEquals(0, connector.getConnectCount());
272         assertEquals(0, connector.getStartCount());
273         assertEquals(0, connector.getStopCount());
274         assertEquals(0, connector.getDisconnectCount());
275         assertEquals(1, connector.getDisposeCount());
276 
277         try
278         {
279             connector.dispose();
280             fail("cannot dispose the connector twice");
281         }
282         catch (IllegalStateException e)
283         {
284             //expected
285         }
286         assertEquals(1, connector.getInitialiseCount());
287         assertEquals(0, connector.getConnectCount());
288         assertEquals(0, connector.getStartCount());
289         assertEquals(0, connector.getStopCount());
290         assertEquals(0, connector.getDisconnectCount());
291         assertEquals(1, connector.getDisposeCount());
292     }
293 
294     @Test
295     public void testReceiversLifecycle() throws Exception
296     {
297         Service service=getTestService();
298         service.start();
299         connector.registerListener(getTestInboundEndpoint("in", "test://in"), getSensingNullMessageProcessor(), service);
300 
301         assertEquals(1, connector.receivers.size());
302         assertFalse(( connector.receivers.get("in")).isConnected());
303         assertFalse(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
304 
305         connector.start();
306         assertTrue(( connector.receivers.get("in")).isConnected());
307         assertTrue(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
308 
309         connector.registerListener(getTestInboundEndpoint("in2", "test://in2"), getSensingNullMessageProcessor(), service);
310 
311         assertEquals(2, connector.receivers.size());
312         assertTrue(( connector.receivers.get("in")).isConnected());
313         assertTrue(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
314 
315         assertTrue((connector.receivers.get("in2")).isConnected());
316         assertTrue(((AbstractMessageReceiver)connector.receivers.get("in2")).isStarted());
317 
318         connector.stop();
319         assertEquals(2, connector.receivers.size());
320         assertTrue(( connector.receivers.get("in")).isConnected());
321         assertFalse(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
322         assertTrue(( connector.receivers.get("in2")).isConnected());
323         assertFalse(((AbstractMessageReceiver) connector.receivers.get("in2")).isStarted());
324 
325         connector.disconnect();
326         assertEquals(2, connector.receivers.size());
327         assertFalse(( connector.receivers.get("in")).isConnected());
328         assertFalse(( connector.receivers.get("in2")).isConnected());
329 
330         connector.start();
331         assertEquals(2, connector.receivers.size());
332         assertTrue((connector.receivers.get("in")).isConnected());
333         assertTrue(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
334         assertTrue((connector.receivers.get("in2")).isConnected());
335         assertTrue(((AbstractMessageReceiver) connector.receivers.get("in2")).isStarted());
336 
337         connector.dispose();
338         assertEquals(0, connector.receivers.size());
339 
340     }
341 
342     @Test
343     public void testReceiversServiceLifecycle() throws Exception
344     {
345         Service service = getTestService();
346         InboundEndpoint endpoint = getTestInboundEndpoint("in", "test://in");
347         ((CompositeMessageSource) service.getMessageSource()).addSource(endpoint);
348         connector = (TestConnector) endpoint.getConnector();
349 
350         assertEquals(0, connector.receivers.size());
351 
352         connector.start();
353         assertEquals(0, connector.receivers.size());
354 
355         service.start();
356         assertEquals(1, connector.receivers.size());
357         assertTrue(( connector.receivers.get("in")).isConnected());
358         assertTrue(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
359 
360         connector.stop();
361         assertEquals(1, connector.receivers.size());
362         assertTrue(( connector.receivers.get("in")).isConnected());
363         assertFalse(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
364 
365         connector.disconnect();
366         assertEquals(1, connector.receivers.size());
367         assertFalse(( connector.receivers.get("in")).isConnected());
368 
369         connector.start();
370         assertEquals(1, connector.receivers.size());
371         assertTrue(( connector.receivers.get("in")).isConnected());
372         assertTrue(((AbstractMessageReceiver) connector.receivers.get("in")).isStarted());
373 
374         service.stop();
375         assertEquals(0, connector.receivers.size());
376 
377         connector.stop();
378         assertEquals(0, connector.receivers.size());
379     }
380 
381     @Test
382     public void testDispatchersLifecycle() throws Exception
383     {
384         //using sync endpoint so that any calls to 'process()' will be blocking and avoid timing issues
385         OutboundEndpoint out = getTestOutboundEndpoint("out", 
386             "test://out?exchangePattern=request-response", null, null, null, connector);
387 
388         // attempts to send/dispatch/request are made on a stopped/stopping connector
389         // This should fail because the connector is not started!
390         try
391         {
392             out.process(getTestEvent("data"));
393             fail("cannot send on a connector that is not started");
394         }
395         catch (LifecycleException e)
396         {
397             // expected
398         }
399 
400         assertEquals(0, connector.dispatchers.getNumIdle());
401 
402         // Dispatcher is not started or connected
403         assertDispatcherStartedConnected(out, false, false);
404 
405         connector.start();
406         //This causes the first instance out dispatcher to be created
407         assertDispatcherStartedConnected(out, true, true);
408 
409         OutboundEndpoint out2 = getTestOutboundEndpoint("out2", 
410             "test://out2?exchangePattern=request-response", null, null, null, connector);
411         //This causes the first instance out2 dispatcher to be created
412         out2.process(getTestEvent("data"));
413 
414         //At this point there should be two idle, but the build server reports one, I suspect its a timing issues
415         assertEquals(2, connector.dispatchers.getNumIdle());
416         assertDispatcherStartedConnected(out, true, true);
417         assertDispatcherStartedConnected(out2, true, true);
418 
419         connector.stop();
420 
421         // Pool is cleared because of implementation of workaround for MULE-4553
422         assertEquals(0, connector.dispatchers.getNumActive() + connector.dispatchers.getNumIdle());
423         assertDispatcherStartedConnected(out, false, false);
424         assertDispatcherStartedConnected(out2, false, false);
425 
426         connector.start();
427 
428         assertEquals(2, connector.dispatchers.getNumActive() + connector.dispatchers.getNumIdle());
429         assertDispatcherStartedConnected(out, true, true);
430         assertDispatcherStartedConnected(out2, true, true);
431 
432         out.process(getTestEvent("data"));
433         assertEquals(2, connector.dispatchers.getNumIdle());
434         assertDispatcherStartedConnected(out, true, true);
435 
436         connector.dispose();
437         assertEquals(0, connector.dispatchers.getNumActive() + connector.dispatchers.getNumIdle());
438 
439     }
440 
441     @Test
442     public void testDispatcherFullLifecycle() throws Exception
443     {
444         OutboundEndpoint out = getTestOutboundEndpoint("out", "test://out", null, null, null, connector);
445 
446         MessageDispatcher dispatcher = connector.getDispatcherFactory().create(out);
447         dispatcher.initialise();
448         
449         assertTrue(dispatcher.getLifecycleState().isInitialised());
450         dispatcher.connect();
451         assertTrue(dispatcher.isConnected());
452 
453         dispatcher.start();
454         assertTrue(dispatcher.getLifecycleState().isStarted());
455 
456         dispatcher.stop();
457         assertTrue(dispatcher.getLifecycleState().isStopped());
458 
459         dispatcher.disconnect();
460         assertFalse(dispatcher.isConnected());
461 
462         dispatcher.dispose();
463         assertTrue(dispatcher.getLifecycleState().isDisposed());
464 
465     }
466 
467     @Test
468     public void testRequestersLifecycle() throws Exception
469     {
470         InboundEndpoint in = getTestInboundEndpoint("in", "test://in", null, null, null, connector);
471 
472         // attempts to send/dispatch/request are made on a stopped/stopping connector
473         // This should fail because the connector is not started!
474         try
475         {
476             in.request(1000L);
477             fail("cannot sent on a connector that is not started");
478         }
479         catch (LifecycleException e)
480         {
481             //Expected
482         }
483 
484 
485         assertEquals(0, connector.requesters.getNumIdle());
486 
487         // Dispatcher is not started or connected
488         assertRequesterStartedConnected(in, false, false);
489 
490         connector.start();
491         assertRequesterStartedConnected(in, true, true);
492 
493         assertEquals(1, connector.requesters.getNumIdle());
494 
495         InboundEndpoint in2 = getTestInboundEndpoint("in2", "test://in2", null, null, null, connector);
496         in2.request(1000L);
497 
498 
499         assertEquals(2, connector.requesters.getNumIdle());
500         assertRequesterStartedConnected(in, true, true);
501         assertRequesterStartedConnected(in2, true, true);
502 
503         connector.stop();
504 
505         // Pool is cleared because of implementation of workaround for MULE-4553
506         assertEquals(0, connector.requesters.getNumActive() + connector.requesters.getNumIdle());
507         assertRequesterStartedConnected(in, false, false);
508         assertRequesterStartedConnected(in2, false, false);
509 
510         connector.start();
511         //Between Stop and start the requester pool maintains existing pooled objects
512         assertEquals(2, connector.requesters.getNumActive() + connector.requesters.getNumIdle());
513         assertRequesterStartedConnected(in, true, true);
514         assertRequesterStartedConnected(in2, true, true);
515 
516         in.request(1000L);
517         assertEquals(2, connector.requesters.getNumIdle());
518         assertRequesterStartedConnected(in, true, true);
519 
520         connector.dispose();
521         assertEquals(0, connector.requesters.getNumActive() + connector.requesters.getNumIdle());
522 
523     }
524 
525     @Test
526     public void testRequesterFullLifecycle() throws Exception
527     {
528         InboundEndpoint in = getTestInboundEndpoint("out", "test://out", null, null, null, connector);
529 
530         MessageRequester requester = connector.getRequesterFactory().create(in);
531 
532         requester.initialise();
533         assertTrue(requester.getLifecycleState().isInitialised());
534 
535         requester.connect();
536         assertTrue(requester.isConnected());
537 
538         requester.start();
539         assertTrue(requester.getLifecycleState().isStarted());
540 
541         requester.stop();
542         assertTrue(requester.getLifecycleState().isStopped());
543 
544         requester.disconnect();
545         assertFalse(requester.isConnected());
546 
547         requester.dispose();
548         assertTrue(requester.getLifecycleState().isDisposed());
549 
550     }
551 
552     @Test
553     public void testWorkManagerLifecycle() throws MuleException, WorkException
554     {
555         //ConnectorLifecycleTestCase These are now created in the "initialize" phase
556         //   assertNull(connector.getReceiverWorkManager());
557         //   assertNull(connector.getDispatcherWorkManager());
558         //   assertNull(connector.getRequesterWorkManager());
559 
560         connector.start();
561         assertNotNull(connector.getReceiverWorkManager());
562         assertNotNull(connector.getDispatcherWorkManager());
563         assertNotNull(connector.getRequesterWorkManager());
564         connector.getReceiverWorkManager().doWork(createSomeWork());
565         connector.getDispatcherWorkManager().doWork(createSomeWork());
566         connector.getRequesterWorkManager().doWork(createSomeWork());
567 
568         connector.stop();
569         assertNull(connector.getReceiverWorkManager());
570         assertNull(connector.getDispatcherWorkManager());
571         assertNull(connector.getRequesterWorkManager());
572 
573         connector.start();
574         assertNotNull(connector.getReceiverWorkManager());
575         assertNotNull(connector.getDispatcherWorkManager());
576         assertNotNull(connector.getRequesterWorkManager());
577         connector.getReceiverWorkManager().doWork(createSomeWork());
578         connector.getDispatcherWorkManager().doWork(createSomeWork());
579         connector.getRequesterWorkManager().doWork(createSomeWork());
580 
581         connector.dispose();
582         assertNull(connector.getReceiverWorkManager());
583         assertNull(connector.getDispatcherWorkManager());
584         assertNull(connector.getRequesterWorkManager());
585     }
586 
587     @Test
588     public void testSchedulerLifecycle() throws MuleException, WorkException
589     {
590         assertNull(connector.getScheduler());
591 
592         connector.start();
593         assertFalse(connector.getScheduler().isShutdown());
594         assertFalse(connector.getScheduler().isTerminated());
595 
596         connector.stop();
597         assertNull(connector.getScheduler());
598 
599         connector.start();
600         assertFalse(connector.getScheduler().isShutdown());
601         assertFalse(connector.getScheduler().isTerminated());
602 
603         connector.dispose();
604         assertNull(connector.getScheduler());
605     }
606 
607     protected Work createSomeWork()
608     {
609         return new Work()
610         {
611             public void run()
612             {
613                 System.out.println("I'm doing some work");
614             }
615 
616             public void release()
617             {
618                 // nothing to do
619             }
620         };
621     }
622 
623     private void assertDispatcherStartedConnected(OutboundEndpoint out, boolean started, boolean connected)
624             throws Exception
625     {
626         AbstractMessageDispatcher dispatcher = (AbstractMessageDispatcher) connector.dispatchers.borrowObject(out);
627         assertEquals("Dispatcher started", started, dispatcher.isStarted());
628         assertEquals("Dispatcher connected", connected, dispatcher.isConnected());
629         connector.dispatchers.returnObject(out, dispatcher);
630     }
631 
632     private void assertRequesterStartedConnected(InboundEndpoint in, boolean started, boolean connected)
633             throws Exception
634     {
635         AbstractMessageRequester requester = (AbstractMessageRequester) connector.requesters.borrowObject(in);
636         assertEquals("Requester started", started, requester.isStarted());
637         assertEquals("requester connected", connected, requester.isConnected());
638         connector.requesters.returnObject(in, requester);
639     }
640 }