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