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