View Javadoc

1   /*
2    * $Id: PooledJavaComponentTestCase.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.component;
12  
13  import org.mule.api.component.LifecycleAdapter;
14  import org.mule.api.lifecycle.InitialisationException;
15  import org.mule.api.object.ObjectFactory;
16  import org.mule.config.PoolingProfile;
17  import org.mule.object.PrototypeObjectFactory;
18  import org.mule.tck.services.UniqueComponent;
19  import org.mule.tck.testmodels.fruit.Orange;
20  import org.mule.tck.testmodels.fruit.WaterMelon;
21  import org.mule.util.ExceptionUtils;
22  import org.mule.util.pool.AbstractPoolingTestCase;
23  
24  import java.util.NoSuchElementException;
25  
26  import org.junit.Test;
27  
28  import static org.junit.Assert.assertEquals;
29  import static org.junit.Assert.assertFalse;
30  import static org.junit.Assert.assertNotNull;
31  import static org.junit.Assert.assertNotSame;
32  import static org.junit.Assert.assertNull;
33  import static org.junit.Assert.assertTrue;
34  import static org.junit.Assert.fail;
35  
36  public class PooledJavaComponentTestCase extends AbstractPoolingTestCase
37  {    
38      @Test
39      public void testComponentCreation() throws Exception
40      {
41          PrototypeObjectFactory objectFactory = getDefaultObjectFactory();
42  
43          PoolingProfile pp = createDefaultPoolingProfile();
44          pp.setExhaustedAction(PoolingProfile.WHEN_EXHAUSTED_FAIL);
45  
46          PooledJavaComponent component = new PooledJavaComponent(objectFactory, pp);
47          component.setMuleContext(muleContext);
48          assertNotNull(component.getObjectFactory());
49          assertEquals(objectFactory, component.getObjectFactory());
50          assertEquals(Orange.class, component.getObjectType());
51  
52          assertNotNull(component.getPoolingProfile());
53          assertEquals(pp, component.getPoolingProfile());
54      }
55  
56      @Test
57      public void testPoolManagement() throws Exception
58      {
59          PooledJavaComponent component = new PooledJavaComponent(getDefaultObjectFactory(), createDefaultPoolingProfile());
60          assertNull(component.lifecycleAdapterPool);
61          
62          component.setFlowConstruct(getTestService());
63          component.setMuleContext(muleContext);
64          component.initialise();
65          assertNull(component.lifecycleAdapterPool);
66          
67          component.start();
68          assertNotNull(component.lifecycleAdapterPool);
69          
70          component.stop();
71          assertNull(component.lifecycleAdapterPool);
72      }
73  
74      @Test
75      public void testStartStop() throws Exception
76      {
77          PooledJavaComponent component = createPooledComponent();
78          assertNotSame(component.borrowComponentLifecycleAdaptor(), component.borrowComponentLifecycleAdaptor());
79          
80          component.stop();
81          component.start();
82  
83          Object la1 = ((DefaultComponentLifecycleAdapter) component.borrowComponentLifecycleAdaptor()).componentObject;
84          Object la2 = ((DefaultComponentLifecycleAdapter) component.borrowComponentLifecycleAdaptor()).componentObject;
85          assertNotSame(la1, la2);
86      }
87  
88      @Test
89      public void testCreateLifecycleAdapters() throws Exception
90      {
91          PooledJavaComponent component = createPooledComponent();
92          assertEquals(0, component.lifecycleAdapterPool.getNumActive());
93  
94          LifecycleAdapter borrowed = component.borrowComponentLifecycleAdaptor();
95          assertNotNull(borrowed);
96          assertEquals(1, component.lifecycleAdapterPool.getNumActive());
97          
98          component.returnComponentLifecycleAdaptor(borrowed);
99          assertEquals(0, component.lifecycleAdapterPool.getNumActive());
100 
101         borrowed = component.borrowComponentLifecycleAdaptor();
102         assertNotNull(borrowed);
103         assertEquals(1, component.lifecycleAdapterPool.getNumActive());
104         
105         Object borrowed2 = component.borrowComponentLifecycleAdaptor();
106         assertNotNull(borrowed2);
107         assertEquals(2, component.lifecycleAdapterPool.getNumActive());
108     }
109 
110     @Test
111     public void testFailOnExhaust() throws Exception
112     {
113         PoolingProfile pp = createDefaultPoolingProfile();
114         pp.setExhaustedAction(PoolingProfile.WHEN_EXHAUSTED_FAIL);
115         
116         PooledJavaComponent component = createPooledComponent(pp);
117         borrowLifecycleAdaptersUntilPoolIsFull(component);
118 
119         try
120         {
121             component.borrowComponentLifecycleAdaptor();
122             fail("Should throw an Exception");
123         }
124         catch (NoSuchElementException nse)
125         {
126             // expected
127         }
128     }
129 
130     @Test
131     public void testBlockExpiryOnExhaust() throws Exception
132     {
133         PoolingProfile pp = createDefaultPoolingProfile();
134         pp.setExhaustedAction(PoolingProfile.WHEN_EXHAUSTED_WAIT);
135         
136         PooledJavaComponent component = createPooledComponent(pp);
137         assertEquals(0, component.lifecycleAdapterPool.getNumActive());
138         
139         borrowLifecycleAdaptersUntilPoolIsFull(component);
140 
141         long startTime = System.currentTimeMillis();
142         try
143         {
144             component.borrowComponentLifecycleAdaptor();
145             fail("Should throw an Exception");
146         }
147         catch (NoSuchElementException e)
148         {
149             long totalTime = System.currentTimeMillis() - startTime;
150             assertTrue(totalTime >= MAX_WAIT);
151         }
152     }
153 
154     @Test
155     public void testBlockOnExhaust() throws Exception
156     {
157         PoolingProfile pp = createDefaultPoolingProfile();
158         pp.setExhaustedAction(PoolingProfile.WHEN_EXHAUSTED_WAIT);
159         
160         PooledJavaComponent component = createPooledComponent(pp);
161         assertEquals(0, component.lifecycleAdapterPool.getNumActive());
162 
163         // borrow all but one lifecycle adapters
164         int oneRemainingInPool = (MAX_ACTIVE - 1);
165         for (int i = 0; i < oneRemainingInPool; i++)
166         {
167             LifecycleAdapter borrowed = component.borrowComponentLifecycleAdaptor();
168             assertNotNull(borrowed);
169             assertEquals(component.lifecycleAdapterPool.getNumActive(), i + 1);
170         }
171         assertEquals(oneRemainingInPool, component.lifecycleAdapterPool.getNumActive());
172         
173         long startTime = System.currentTimeMillis();
174         int borrowerWait = 500;
175         Borrower borrower = new Borrower(component, borrowerWait);
176         new Thread(borrower, "BorrowThread").start();
177 
178         // Make sure the borrower borrows first
179         try
180         {
181             Thread.sleep(200);
182         }
183         catch (InterruptedException e)
184         {
185             // ignore
186         }
187 
188         // this will get an object from the pool eventually, after Borrower has returned it
189         Object borrowed = component.borrowComponentLifecycleAdaptor();
190         assertNotNull(borrowed);
191         long totalTime = System.currentTimeMillis() - startTime;
192         assertTrue(totalTime >= borrowerWait);
193     }
194     
195     @Test
196     public void testGrowOnExhaust() throws Exception
197     {
198         PoolingProfile pp = createDefaultPoolingProfile();
199         pp.setExhaustedAction(PoolingProfile.WHEN_EXHAUSTED_GROW);
200         
201         PooledJavaComponent component = createPooledComponent(pp);
202 
203         borrowLifecycleAdaptersUntilPoolIsFull(component);
204 
205         // Should now grow
206         Object borrowed = component.borrowComponentLifecycleAdaptor();
207         assertNotNull(borrowed);
208         assertEquals(MAX_ACTIVE + 1, component.lifecycleAdapterPool.getNumActive());
209     }
210 
211     @Test
212     public void testClearPool() throws Exception
213     {
214         PoolingProfile pp = createDefaultPoolingProfile();
215         pp.setExhaustedAction(PoolingProfile.WHEN_EXHAUSTED_FAIL);
216         
217         PooledJavaComponent component = createPooledComponent(pp);
218 
219         LifecycleAdapter borrowed = component.borrowComponentLifecycleAdaptor();
220         assertEquals(1, component.lifecycleAdapterPool.getNumActive());
221         component.returnComponentLifecycleAdaptor(borrowed);
222         assertEquals(0, component.lifecycleAdapterPool.getNumActive());
223 
224         component.stop();
225         component.start();
226         assertEquals(0, component.lifecycleAdapterPool.getNumActive());
227     }
228 
229     @Test
230     public void testObjectUniqueness() throws Exception
231     {
232         PrototypeObjectFactory objectFactory = new PrototypeObjectFactory(UniqueComponent.class);
233         PooledJavaComponent component = createPooledComponent(objectFactory);
234         assertEquals(0, component.lifecycleAdapterPool.getNumActive());
235 
236         String id1 = getIdFromObjectCreatedByPool(component);
237         String id2 = getIdFromObjectCreatedByPool(component);
238         String id3 = getIdFromObjectCreatedByPool(component);
239 
240         assertFalse("Service IDs " + id1 + " and " + id2 + " should be different", id1.equals(id2));
241         assertFalse("Service IDs " + id2 + " and " + id3 + " should be different", id2.equals(id3));
242         assertFalse("Service IDs " + id1 + " and " + id3 + " should be different", id1.equals(id3));
243     }
244     
245     @Test
246     public void testDisposingFactoryDisposesObject() throws Exception
247     {
248         PrototypeObjectFactory objectFactory = new PrototypeObjectFactory(WaterMelon.class);
249         PooledJavaComponent component = createPooledComponent(objectFactory);
250 
251         DefaultComponentLifecycleAdapter lifecycleAdapter = (DefaultComponentLifecycleAdapter) component.borrowComponentLifecycleAdaptor();
252         component.returnComponentLifecycleAdaptor(lifecycleAdapter);
253         component.stop();
254         component.dispose();
255 
256         assertNull(lifecycleAdapter.componentObject);
257     }
258     
259     private PrototypeObjectFactory getDefaultObjectFactory() throws InitialisationException
260     {
261         PrototypeObjectFactory objectFactory = new PrototypeObjectFactory(Orange.class);
262         objectFactory.initialise();
263         return objectFactory;
264     }
265     
266     private PooledJavaComponent createPooledComponent() throws Exception
267     {
268         return createPooledComponent(createDefaultPoolingProfile(), getDefaultObjectFactory());
269     }
270 
271     private PooledJavaComponent createPooledComponent(ObjectFactory objectFactory) throws Exception
272     {
273         return createPooledComponent(createDefaultPoolingProfile(), objectFactory);
274     }
275     
276     private PooledJavaComponent createPooledComponent(PoolingProfile poolingProfile) throws Exception
277     {
278         return createPooledComponent(poolingProfile, getDefaultObjectFactory());
279     }
280     
281     private PooledJavaComponent createPooledComponent(PoolingProfile poolingProfile, ObjectFactory objectFactory) throws Exception
282     {
283         PooledJavaComponent component = new PooledJavaComponent(objectFactory, poolingProfile);
284         component.setMuleContext(muleContext);
285         component.setFlowConstruct(getTestService());
286         component.initialise();
287         component.start();
288         return component;
289     }
290     
291     private void borrowLifecycleAdaptersUntilPoolIsFull(PooledJavaComponent component) throws Exception
292     {
293         for (int i = 0; i < MAX_ACTIVE; i++)
294         {
295             Object borrowed = component.borrowComponentLifecycleAdaptor();
296             assertNotNull(borrowed);
297             assertEquals(component.lifecycleAdapterPool.getNumActive(), i + 1);
298         }
299         assertEquals(MAX_ACTIVE, component.lifecycleAdapterPool.getNumActive());
300     }
301 
302     private String getIdFromObjectCreatedByPool(PooledJavaComponent component) throws Exception
303     {
304         DefaultComponentLifecycleAdapter lifecycleAdapter = 
305             (DefaultComponentLifecycleAdapter) component.borrowComponentLifecycleAdaptor();
306         Object obj = lifecycleAdapter.componentObject;
307         
308         // there is a slight chance that GC kicks in before we can get a hard reference to the 
309         // object. If this occurs, talk do Dirk and Andrew P about how to fix this
310         assertNotNull(obj);
311         
312         assertTrue("Object should be of type UniqueComponent", obj instanceof UniqueComponent);
313      
314         String id = ((UniqueComponent) obj).getId();
315         assertNotNull(id);
316         return id;
317     }
318     
319     private static class Borrower implements Runnable
320     {
321         private PooledJavaComponent component;
322         private long time;
323 
324         public Borrower(PooledJavaComponent component, long time)
325         {
326             super();
327             if (component == null)
328             {
329                 throw new IllegalArgumentException("Pool cannot be null");
330             }
331             this.component = component;
332             if (time < 500)
333             {
334                 time = 500;
335             }
336             this.time = time;
337         }
338 
339         public void run()
340         {
341             try
342             {
343                 LifecycleAdapter object = component.borrowComponentLifecycleAdaptor();
344                 try
345                 {
346                     Thread.sleep(time);
347                 }
348                 catch (InterruptedException e)
349                 {
350                     // ignore
351                 }
352                 component.returnComponentLifecycleAdaptor(object);
353             }
354             catch (Exception e)
355             {
356                 fail("Borrower thread failed:\n" + ExceptionUtils.getStackTrace(e));
357             }
358         }
359     }
360 }