View Javadoc

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