1   /*
2    * Copyright 1999-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.pool.impl;
18  
19  import java.util.BitSet;
20  import java.util.NoSuchElementException;
21  import java.util.List;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  
25  import junit.framework.Test;
26  import junit.framework.TestSuite;
27  
28  import org.apache.commons.pool.ObjectPool;
29  import org.apache.commons.pool.PoolableObjectFactory;
30  import org.apache.commons.pool.TestObjectPool;
31  
32  /***
33   * @author Rodney Waldhoff
34   * @author Dirk Verbeeck
35   * @version $Revision: 383290 $ $Date: 2006-03-05 02:00:15 -0500 (Sun, 05 Mar 2006) $
36   */
37  public class TestStackObjectPool extends TestObjectPool {
38      public TestStackObjectPool(String testName) {
39          super(testName);
40      }
41  
42      public static Test suite() {
43          return new TestSuite(TestStackObjectPool.class);
44      }
45  
46      protected ObjectPool makeEmptyPool(int mincap) {
47          return new StackObjectPool(new SimpleFactory());
48      }
49      
50      protected Object getNthObject(int n) {
51          return String.valueOf(n);
52      }
53  
54      public void testIdleCap() throws Exception {
55          ObjectPool pool = makeEmptyPool(8);
56          Object[] active = new Object[100];
57          for(int i=0;i<100;i++) {
58              active[i] = pool.borrowObject();
59          }
60          assertEquals(100,pool.getNumActive());
61          assertEquals(0,pool.getNumIdle());
62          for(int i=0;i<100;i++) {
63              pool.returnObject(active[i]);
64              assertEquals(99 - i,pool.getNumActive());
65              assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
66          }
67      }
68  
69      public void testPoolWithNullFactory() throws Exception {
70          ObjectPool pool = new StackObjectPool(10);
71          for(int i=0;i<10;i++) {
72              pool.returnObject(new Integer(i));
73          }
74          for(int j=0;j<3;j++) {
75              Integer[] borrowed = new Integer[10];
76              BitSet found = new BitSet();
77              for(int i=0;i<10;i++) {
78                  borrowed[i] = (Integer)(pool.borrowObject());
79                  assertNotNull(borrowed);
80                  assertTrue(!found.get(borrowed[i].intValue()));
81                  found.set(borrowed[i].intValue());
82              }
83              for(int i=0;i<10;i++) {
84                  pool.returnObject(borrowed[i]);
85              }
86          }
87          pool.invalidateObject(pool.borrowObject());
88          pool.invalidateObject(pool.borrowObject());
89          pool.clear();        
90      }
91      
92      public void testBorrowFromEmptyPoolWithNullFactory() throws Exception {
93          ObjectPool pool = new StackObjectPool();
94          try {
95              pool.borrowObject();
96              fail("Expected NoSuchElementException");
97          } catch(NoSuchElementException e) {
98              // expected
99          }
100     }
101     
102     public void testSetFactory() throws Exception {
103         ObjectPool pool = new StackObjectPool();
104         try {
105             pool.borrowObject();
106             fail("Expected NoSuchElementException");
107         } catch(NoSuchElementException e) {
108             // expected
109         }
110         pool.setFactory(new SimpleFactory());
111         Object obj = pool.borrowObject();
112         assertNotNull(obj);
113         pool.returnObject(obj);
114     }
115 
116     public void testCantResetFactoryWithActiveObjects() throws Exception {
117         ObjectPool pool = new StackObjectPool();
118         pool.setFactory(new SimpleFactory());
119         Object obj = pool.borrowObject();
120         assertNotNull(obj);
121 
122         try {
123             pool.setFactory(new SimpleFactory());
124             fail("Expected IllegalStateException");
125         } catch(IllegalStateException e) {
126             // expected
127         }        
128     }
129     
130     public void testCanResetFactoryWithoutActiveObjects() throws Exception {
131         ObjectPool pool = new StackObjectPool();
132         {
133             pool.setFactory(new SimpleFactory());
134             Object obj = pool.borrowObject();        
135             assertNotNull(obj);
136             pool.returnObject(obj);
137         }
138         {
139             pool.setFactory(new SimpleFactory());
140             Object obj = pool.borrowObject();        
141             assertNotNull(obj);
142             pool.returnObject(obj);
143         }
144     }
145 
146 
147     public void testBorrowWithSometimesInvalidObjects() throws Exception {
148         ObjectPool pool = new StackObjectPool(20);
149         pool.setFactory(
150             new PoolableObjectFactory() {
151                 // factory makes Integer objects
152                 int counter = 0;
153                 public Object makeObject() { return new Integer(counter++); }
154                 public void destroyObject(Object obj) { }
155                 public boolean validateObject(Object obj) {
156                     // only odd objects are valid
157                     if(obj instanceof Integer) {
158                         return ((((Integer)obj).intValue() % 2) == 1);
159                     } else {
160                         return false;
161                     }
162                 }
163                 public void activateObject(Object obj) { }
164                 public void passivateObject(Object obj) { 
165                     if(obj instanceof Integer) {
166                         if((((Integer)obj).intValue() % 3) == 0) {
167                             throw new RuntimeException("Couldn't passivate");
168                         }
169                     } else {
170                         throw new RuntimeException("Couldn't passivate");
171                     }
172                 }
173             }
174         );
175 
176         Object[] obj = new Object[10];
177         for(int i=0;i<10;i++) {
178             obj[i] = pool.borrowObject();
179             assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive());
180             
181         }
182         for(int i=0;i<10;i++) {
183             pool.returnObject(obj[i]);
184             assertEquals("Each time we borrow, get one less active.", 9-i, pool.getNumActive());
185         }
186         assertEquals(7,pool.getNumIdle());
187     }
188     
189     public void testBorrowReturnWithSometimesInvalidObjects() throws Exception {
190         ObjectPool pool = new StackObjectPool(20);
191 
192         class TestingPoolableObjectFactory implements PoolableObjectFactory {
193             // factory makes Integer objects
194             int counter = 0;
195             boolean reject = false;
196             public Object makeObject() { return new Integer(counter++); }
197             public void destroyObject(Object obj) { }
198             public boolean validateObject(Object obj) {
199                 if (reject) {
200                     // only odd objects are valid
201                     if(obj instanceof Integer) {
202                         return ((((Integer)obj).intValue() % 2) == 1);
203                     } else {
204                         return false;
205                     }
206                 } else {
207                     return true;
208                 }
209                     
210             }
211             public void activateObject(Object obj) { }
212             public void passivateObject(Object obj) { 
213                 if(obj instanceof Integer) {
214                     if((((Integer)obj).intValue() % 3) == 0) {
215                         throw new RuntimeException("Couldn't passivate");
216                     }
217                 } else {
218                     throw new RuntimeException("Couldn't passivate");
219                 }
220             }
221         };
222         
223         TestingPoolableObjectFactory factory = new TestingPoolableObjectFactory();
224         
225         pool.setFactory(factory);
226 
227         Object[] obj = new Object[10];
228         for(int i=0;i<10;i++) {
229             obj[i] = pool.borrowObject();
230             assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive());
231             
232         }
233         
234         // now reject even numbers
235         factory.reject = true;
236         
237         for(int i=0;i<10;i++) {
238             pool.returnObject(obj[i]);
239             assertEquals("Each time we borrow, get one less active.", 9-i, pool.getNumActive());
240         }
241         assertEquals(3,pool.getNumIdle());
242     }
243     
244     public void testVariousConstructors() throws Exception {
245         {
246             StackObjectPool pool = new StackObjectPool();
247             assertNotNull(pool);
248         }
249         {
250             StackObjectPool pool = new StackObjectPool(10);
251             assertNotNull(pool);
252         }
253         {
254             StackObjectPool pool = new StackObjectPool(10,5);
255             assertNotNull(pool);
256         }
257         {
258             StackObjectPool pool = new StackObjectPool(null);
259             assertNotNull(pool);
260         }
261         {
262             StackObjectPool pool = new StackObjectPool(null,10);
263             assertNotNull(pool);
264         }
265         {
266             StackObjectPool pool = new StackObjectPool(null,10,5);
267             assertNotNull(pool);
268         }
269     }
270 
271     private final List destroyed = new ArrayList();
272     public void testReturnObjectDiscardOrder() throws Exception {
273         // setup
274         // We need a factory that tracks what was discarded.
275         PoolableObjectFactory pof = new PoolableObjectFactory() {
276             int i = 0;
277             public Object makeObject() throws Exception {
278                 return new Integer(i++);
279             }
280 
281             public void destroyObject(Object obj) throws Exception {
282                 destroyed.add(obj);
283             }
284 
285             public boolean validateObject(Object obj) {
286                 return obj instanceof Integer;
287             }
288 
289             public void activateObject(Object obj) throws Exception {
290             }
291 
292             public void passivateObject(Object obj) throws Exception {
293             }
294         };
295         ObjectPool pool = new StackObjectPool(pof, 3);
296 
297         // borrow more objects than the pool can hold
298         Integer i0 = (Integer)pool.borrowObject();
299         Integer i1 = (Integer)pool.borrowObject();
300         Integer i2 = (Integer)pool.borrowObject();
301         Integer i3 = (Integer)pool.borrowObject();
302 
303         // tests
304         // return as many as the pool will hold.
305         pool.returnObject(i0);
306         pool.returnObject(i1);
307         pool.returnObject(i2);
308 
309         // the pool should now be full.
310         assertEquals("No returned objects should have been destroyed yet.",0, destroyed.size());
311 
312         // cause the pool to discard a returned object.
313         pool.returnObject(i3);
314         assertEquals("One object should have been destroyed.", 1, destroyed.size());
315 
316         // check to see what object was destroyed
317         Integer d = (Integer)destroyed.get(0);
318         assertEquals("Destoryed objects should have the stalest object.", i0, d);
319     }
320 
321     private List testFactorySequenceStates = new ArrayList(5);
322     public void testFactorySequence() throws Exception {
323         // setup
324         // We need a factory that tracks method call sequence.
325         PoolableObjectFactory pof = new PoolableObjectFactory() {
326             public Object makeObject() throws Exception {
327                 testFactorySequenceStates.add("makeObject");
328                 return new Object();
329             }
330 
331             public void activateObject(Object obj) throws Exception {
332                 testFactorySequenceStates.add("activateObject");
333             }
334 
335             public boolean validateObject(Object obj) {
336                 testFactorySequenceStates.add("validateObject");
337                 return true;
338             }
339 
340             public void passivateObject(Object obj) throws Exception {
341                 testFactorySequenceStates.add("passivateObject");
342             }
343 
344             public void destroyObject(Object obj) throws Exception {
345                 testFactorySequenceStates.add("destroyObject");
346             }
347         };
348 
349         ObjectPool pool = new StackObjectPool(pof, 1);
350 
351         // check the order in which the factory is called during borrow
352         testFactorySequenceStates.clear();
353         Object o = pool.borrowObject();
354         List desiredSequence = Arrays.asList(new String[] {
355                 "makeObject",
356                 "activateObject",
357                 "validateObject"
358         });
359         assertEquals("Wrong sequence", desiredSequence, testFactorySequenceStates);
360 
361         // check the order in which the factory is called when returning an object
362         testFactorySequenceStates.clear();
363         pool.returnObject(o);
364         desiredSequence = Arrays.asList(new String[] {
365                 "validateObject",
366                 "passivateObject"
367         });
368         assertEquals("Wrong sequence", desiredSequence, testFactorySequenceStates);
369 
370         // check the order in which the factory is called during borrow again
371         testFactorySequenceStates.clear();
372         o = pool.borrowObject();
373         desiredSequence = Arrays.asList(new String[] {
374                 "activateObject",
375                 "validateObject"
376         });
377         assertEquals("Wrong sequence", desiredSequence, testFactorySequenceStates);
378 
379         // check the order in which the factory is called when invalidating an object
380         testFactorySequenceStates.clear();
381         pool.invalidateObject(o);
382         desiredSequence = Arrays.asList(new String[] {
383                 "destroyObject"
384         });
385         assertEquals("Wrong sequence", desiredSequence, testFactorySequenceStates);
386     }
387 
388     static class SimpleFactory implements PoolableObjectFactory {
389         int counter = 0;
390         public Object makeObject() { return String.valueOf(counter++); }
391         public void destroyObject(Object obj) { }
392         public boolean validateObject(Object obj) { return true; }
393         public void activateObject(Object obj) { }
394         public void passivateObject(Object obj) { }
395     }
396 
397     protected boolean isLifo() {
398         return true;
399     }
400 
401     protected boolean isFifo() {
402         return false;
403     }
404 }
405