View Javadoc

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 java.util.ArrayList;
21  import java.util.BitSet;
22  import java.util.List;
23  import java.util.NoSuchElementException;
24  
25  import org.apache.commons.pool.ObjectPool;
26  import org.apache.commons.pool.PoolableObjectFactory;
27  import org.apache.commons.pool.TestBaseObjectPool;
28  
29  /**
30   * @author Rodney Waldhoff
31   * @author Dirk Verbeeck
32   * @author Sandy McArthur
33   * @version $Revision: 960644 $ $Date: 2010-07-05 10:15:07 -0700 (Mon, 05 Jul 2010) $
34   */
35  public class TestStackObjectPool extends TestBaseObjectPool {
36      public TestStackObjectPool(String testName) {
37          super(testName);
38      }
39  
40      protected ObjectPool makeEmptyPool(int mincap) {
41          return new StackObjectPool(new SimpleFactory());
42      }
43  
44      protected ObjectPool makeEmptyPool(final PoolableObjectFactory factory) {
45          return new StackObjectPool(factory);
46      }
47  
48      protected Object getNthObject(int n) {
49          return String.valueOf(n);
50      }
51  
52      public void testIdleCap() throws Exception {
53          ObjectPool pool = makeEmptyPool(8);
54          Object[] active = new Object[100];
55          for(int i=0;i<100;i++) {
56              active[i] = pool.borrowObject();
57          }
58          assertEquals(100,pool.getNumActive());
59          assertEquals(0,pool.getNumIdle());
60          for(int i=0;i<100;i++) {
61              pool.returnObject(active[i]);
62              assertEquals(99 - i,pool.getNumActive());
63              assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
64          }
65      }
66  
67      /**
68       * @deprecated - to be removed in pool 2.0
69       */
70      public void testPoolWithNullFactory() throws Exception {
71          ObjectPool pool = new StackObjectPool(10);
72          for(int i=0;i<10;i++) {
73              pool.returnObject(new Integer(i));
74          }
75          for(int j=0;j<3;j++) {
76              Integer[] borrowed = new Integer[10];
77              BitSet found = new BitSet();
78              for(int i=0;i<10;i++) {
79                  borrowed[i] = (Integer)(pool.borrowObject());
80                  assertNotNull(borrowed);
81                  assertTrue(!found.get(borrowed[i].intValue()));
82                  found.set(borrowed[i].intValue());
83              }
84              for(int i=0;i<10;i++) {
85                  pool.returnObject(borrowed[i]);
86              }
87          }
88          pool.invalidateObject(pool.borrowObject());
89          pool.invalidateObject(pool.borrowObject());
90          pool.clear();        
91      }
92      
93      /**
94       * @deprecated - to be removed in pool 2.0
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     /**
107      * @deprecated - to be removed in pool 2.0
108      */
109     public void testSetFactory() throws Exception {
110         ObjectPool pool = new StackObjectPool();
111         try {
112             pool.borrowObject();
113             fail("Expected NoSuchElementException");
114         } catch(NoSuchElementException e) {
115             // expected
116         }
117         pool.setFactory(new SimpleFactory());
118         Object obj = pool.borrowObject();
119         assertNotNull(obj);
120         pool.returnObject(obj);
121     }
122 
123     /**
124      * @deprecated - to be removed in pool 2.0
125      */
126     public void testCantResetFactoryWithActiveObjects() throws Exception {
127         ObjectPool pool = new StackObjectPool();
128         pool.setFactory(new SimpleFactory());
129         Object obj = pool.borrowObject();
130         assertNotNull(obj);
131 
132         try {
133             pool.setFactory(new SimpleFactory());
134             fail("Expected IllegalStateException");
135         } catch(IllegalStateException e) {
136             // expected
137         }        
138     }
139     
140     /**
141      * @deprecated - to be removed in pool 2.0
142      */
143     public void testCanResetFactoryWithoutActiveObjects() throws Exception {
144         ObjectPool pool = new StackObjectPool();
145         {
146             pool.setFactory(new SimpleFactory());
147             Object obj = pool.borrowObject();        
148             assertNotNull(obj);
149             pool.returnObject(obj);
150         }
151         {
152             pool.setFactory(new SimpleFactory());
153             Object obj = pool.borrowObject();        
154             assertNotNull(obj);
155             pool.returnObject(obj);
156         }
157     }
158 
159     /**
160      * Verifies that validation failures when borrowing newly created instances
161      * from the pool result in NoSuchElementExceptions and passivation failures
162      * result in instances not being returned to the pool.
163      */
164     public void testBorrowWithSometimesInvalidObjects() throws Exception {
165         SelectiveFactory factory = new SelectiveFactory();
166         factory.setValidateSelectively(true);  // Even numbers fail validation
167         factory.setPassivateSelectively(true); // Multiples of 3 fail passivation
168         ObjectPool pool = new StackObjectPool(factory, 20);
169         Object[] obj = new Object[10];
170         for(int i=0;i<10;i++) {
171             Object object = null;
172             int k = 0;
173             while (object == null && k < 100) { // bound not really needed
174                 try {
175                     k++;
176                     object = pool.borrowObject();
177                     if (((Integer) object).intValue() % 2 == 0) {
178                         fail("Expecting NoSuchElementException");
179                     } else {
180                         obj[i] = object; 
181                     }
182                 } catch (NoSuchElementException ex) {
183                     // Should fail for evens
184                 }
185             }
186             assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive());
187         }
188         // 1,3,5,...,19 pass validation, get checked out
189         for(int i=0;i<10;i++) {
190             pool.returnObject(obj[i]);
191             assertEquals("Each time we return, get one less active.", 9-i, pool.getNumActive());
192         }
193         // 3, 9, 15 fail passivation.  
194         assertEquals(7,pool.getNumIdle());
195         assertEquals(new Integer(19), pool.borrowObject());
196         assertEquals(new Integer(17), pool.borrowObject());
197         assertEquals(new Integer(13), pool.borrowObject());
198         assertEquals(new Integer(11), pool.borrowObject());
199         assertEquals(new Integer(7), pool.borrowObject());
200         assertEquals(new Integer(5), pool.borrowObject());
201         assertEquals(new Integer(1), pool.borrowObject());     
202     }
203     
204     /**
205      * Verifies that validation and passivation failures returning objects are handled
206      * properly - instances destroyed and not returned to the pool, but no exceptions propagated.
207      */
208     public void testBorrowReturnWithSometimesInvalidObjects() throws Exception {
209         SelectiveFactory factory = new SelectiveFactory();
210         ObjectPool pool = new StackObjectPool(factory, 20);
211 
212         Object[] obj = new Object[10];
213         for(int i=0;i<10;i++) {
214             obj[i] = pool.borrowObject();
215             assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive());
216             
217         }
218         
219         factory.setValidateSelectively(true);  // Even numbers fail validation
220         factory.setPassivateSelectively(true); // Multiples of 3 fail passivation
221 
222         for(int i=0;i<10;i++) {
223             pool.returnObject(obj[i]);
224             assertEquals("Each time we return, get one less active.", 9-i, pool.getNumActive());
225         }
226         // 0,2,4,6,8 fail validation, 3, 9 fail passivation - 3 left.
227         assertEquals(3,pool.getNumIdle());
228     }
229      
230     public void testVariousConstructors() throws Exception {
231         {
232             StackObjectPool pool = new StackObjectPool();
233             assertNotNull(pool);
234         }
235         {
236             StackObjectPool pool = new StackObjectPool(10);
237             assertNotNull(pool);
238         }
239         {
240             StackObjectPool pool = new StackObjectPool(10,5);
241             assertNotNull(pool);
242         }
243         {
244             StackObjectPool pool = new StackObjectPool(null);
245             assertNotNull(pool);
246         }
247         {
248             StackObjectPool pool = new StackObjectPool(null,10);
249             assertNotNull(pool);
250         }
251         {
252             StackObjectPool pool = new StackObjectPool(null,10,5);
253             assertNotNull(pool);
254         }
255     }
256     
257     /**
258      * Verify that out of range constructor arguments are ignored.
259      */
260     public void testMaxIdleInitCapacityOutOfRange() throws Exception {
261         SimpleFactory factory = new SimpleFactory();
262         StackObjectPool pool = new StackObjectPool(factory, -1, 0);
263         assertEquals(pool.getMaxSleeping(), StackObjectPool.DEFAULT_MAX_SLEEPING);
264         pool.addObject();
265         pool.close();
266     }
267 
268     /**
269      * Verifies that when returning objects cause maxSleeping exceeded, oldest instances
270      * are destroyed to make room for returning objects.
271      */
272     public void testReturnObjectDiscardOrder() throws Exception {
273         SelectiveFactory factory = new SelectiveFactory();
274         ObjectPool pool = new StackObjectPool(factory, 3);
275 
276         // borrow more objects than the pool can hold
277         Integer i0 = (Integer)pool.borrowObject();
278         Integer i1 = (Integer)pool.borrowObject();
279         Integer i2 = (Integer)pool.borrowObject();
280         Integer i3 = (Integer)pool.borrowObject();
281 
282         // tests
283         // return as many as the pool will hold.
284         pool.returnObject(i0);
285         pool.returnObject(i1);
286         pool.returnObject(i2);
287 
288         // the pool should now be full.
289         assertEquals("No returned objects should have been destroyed yet.", 0,  factory.getDestroyed().size());
290 
291         // cause the pool to discard a stale object.
292         pool.returnObject(i3);
293         assertEquals("One object should have been destroyed.", 1, factory.getDestroyed().size());
294 
295         // check to see what object was destroyed
296         Integer d = (Integer)factory.getDestroyed().get(0);
297         assertEquals("Destoryed object should be the stalest object.", i0, d);
298     }
299     
300     /**
301      * Verifies that exceptions thrown by factory activate method are not propagated to
302      * the caller.  Objects that throw on activate are destroyed and if none succeed,
303      * the caller gets NoSuchElementException.
304      */
305     public void testExceptionOnActivate() throws Exception {
306         SelectiveFactory factory = new SelectiveFactory();
307         ObjectPool pool = new StackObjectPool(factory);
308         pool.addObject();
309         pool.addObject();
310         factory.setThrowOnActivate(true);
311         try {
312             pool.borrowObject();
313             fail("Expecting NoSuchElementException");
314         } catch (NoSuchElementException ex) {
315             // expected
316         }
317         assertEquals(0, pool.getNumIdle());
318         assertEquals(0, pool.getNumActive());
319     }
320     
321     /**
322      * Verifies that exceptions thrown by factory destroy are swallowed
323      * by both addObject and returnObject.
324      */
325     public void testExceptionOnDestroy() throws Exception {
326         SelectiveFactory factory = new SelectiveFactory();
327         ObjectPool pool = new StackObjectPool(factory, 2);
328         factory.setThrowOnDestroy(true);
329         for (int i = 0; i < 3; i++) {
330             pool.addObject(); // Third one will destroy, exception should be swallowed
331         }
332         assertEquals(2, pool.getNumIdle());
333         
334         Object[] objects = new Object[3];
335         for (int i = 0; i < 3; i++) {
336             objects[i] = pool.borrowObject();
337         }
338         for (int i = 0; i < 3; i++) {
339             pool.returnObject(objects[i]); // Third triggers destroy
340         } 
341         assertEquals(2, pool.getNumIdle());
342     }
343     
344     /**
345      * Verifies that addObject propagates exceptions thrown by
346      * factory passivate, but returnObject swallows these.
347      */
348     public void testExceptionOnPassivate() throws Exception {
349         SelectiveFactory factory = new SelectiveFactory();
350         ObjectPool pool = new StackObjectPool(factory, 2);
351         factory.setThrowOnPassivate(true);
352         
353         // addObject propagates
354         try {
355             pool.addObject();
356             fail("Expecting IntegerFactoryException");
357         } catch (IntegerFactoryException ex) {
358             assertEquals("passivateObject", ex.getType());
359             assertEquals(0, ex.getValue());
360         }
361         assertEquals(0, pool.getNumIdle());
362         
363         // returnObject swallows 
364         Object obj = pool.borrowObject();
365         pool.returnObject(obj);
366         assertEquals(0, pool.getNumIdle());
367     }
368     
369     /**
370      * Verifies that validation exceptions always propagate
371      */
372     public void testExceptionOnValidate() throws Exception {
373         SelectiveFactory factory = new SelectiveFactory();
374         ObjectPool pool = new StackObjectPool(factory, 2);
375         factory.setThrowOnValidate(true);
376         
377         // addObject
378         try {
379             pool.addObject();
380             fail("Expecting IntegerFactoryException");
381         } catch (IntegerFactoryException ex) {
382             assertEquals("validateObject", ex.getType());
383         }
384         assertEquals(0, pool.getNumIdle());
385         
386         // returnObject 
387         factory.setThrowOnValidate(false);
388         Object obj = pool.borrowObject();
389         factory.setThrowOnValidate(true);
390         try {
391             pool.returnObject(obj);
392             fail("Expecting IntegerFactoryException");
393         } catch (IntegerFactoryException ex) {
394             assertEquals("validateObject", ex.getType());
395         }
396         assertEquals(0, pool.getNumIdle());
397         
398         // borrowObject - throws NoSuchElementException
399         try {
400             pool.borrowObject();
401             fail("Expecting NoSuchElementException");
402         } catch (NoSuchElementException ex) {
403             // Expected
404         }
405     }
406     
407     /**
408      * Verifies that exceptions thrown by makeObject are propagated.
409      */
410     public void testExceptionOnMake() throws Exception {
411         SelectiveFactory factory = new SelectiveFactory();
412         factory.setThrowOnMake(true);
413         ObjectPool pool = new StackObjectPool(factory);
414         try {
415             pool.borrowObject();
416             fail("Expecting IntegerFactoryException");
417         } catch (IntegerFactoryException ex) {
418             assertEquals("makeObject", ex.getType());
419         }
420         try {
421             pool.addObject();
422             fail("Expecting IntegerFactoryException");
423         } catch (IntegerFactoryException ex) {
424             assertEquals("makeObject", ex.getType());
425         }
426     }
427     
428     /**
429      * Verifies NoSuchElementException when the factory returns a null object in borrowObject
430      */
431     public void testMakeNull() throws Exception {
432         SelectiveFactory factory = new SelectiveFactory();
433         ObjectPool pool = new StackObjectPool(factory);
434         factory.setMakeNull(true);
435         try {
436             pool.borrowObject();
437             fail("Expecting NoSuchElementException");
438         } catch (NoSuchElementException ex) {
439             // Expected
440         }
441     }
442     
443     /**
444      * Verifies that initIdleCapacity is not a hard limit, but maxIdle is.
445      */
446     public void testInitIdleCapacityExceeded() throws Exception {
447         PoolableObjectFactory factory = new SimpleFactory();
448         ObjectPool pool = new StackObjectPool(factory, 2, 1);
449         pool.addObject();
450         pool.addObject();
451         assertEquals(2, pool.getNumIdle());
452         pool.close();
453         pool = new StackObjectPool(factory, 1, 2);
454         pool.addObject();
455         pool.addObject();
456         assertEquals(1, pool.getNumIdle());
457     }
458     
459     /**
460      * Verifies close contract - idle instances are destroyed, returning instances
461      * are destroyed, add/borrowObject throw IllegalStateException.
462      */
463     public void testClose() throws Exception {
464         SelectiveFactory factory = new SelectiveFactory();
465         ObjectPool pool = new StackObjectPool(factory);
466         pool.addObject(); // 0
467         pool.addObject(); // 1
468         pool.addObject(); // 2
469         Integer two = (Integer) pool.borrowObject();
470         assertEquals(2, two.intValue());
471         pool.close();
472         assertEquals(0, pool.getNumIdle());
473         assertEquals(1, pool.getNumActive());
474         List destroyed = factory.getDestroyed();
475         assertEquals(2, destroyed.size());
476         assertTrue(destroyed.contains(new Integer(0)));
477         assertTrue(destroyed.contains(new Integer(0)));
478         pool.returnObject(two);
479         assertTrue(destroyed.contains(two));
480         try {
481             pool.addObject();
482             fail("Expecting IllegalStateException");
483         } catch (IllegalStateException ex) {
484             // Expected
485         }
486         try {
487             pool.borrowObject();
488             fail("Expecting IllegalStateException");
489         } catch (IllegalStateException ex) {
490             // Expected
491         }
492     }
493 
494     /**
495      * Simple factory that creates Integers. Validation and other factory methods
496      * always succeed.
497      */
498     static class SimpleFactory implements PoolableObjectFactory {
499         int counter = 0;
500         public Object makeObject() { return String.valueOf(counter++); }
501         public void destroyObject(Object obj) { }
502         public boolean validateObject(Object obj) { return true; }
503         public void activateObject(Object obj) { }
504         public void passivateObject(Object obj) { }
505     }
506     
507     /**
508      * Integer factory that fails validation and other factory methods "selectively" and
509      * tracks object destruction.
510      */
511     static class SelectiveFactory implements PoolableObjectFactory {
512         private List destroyed = new ArrayList();
513         private int counter = 0;
514         private boolean validateSelectively = false;  // true <-> validate returns false for even Integers
515         private boolean passivateSelectively = false; // true <-> passivate throws RTE if Integer = 0 mod 3
516         private boolean throwOnDestroy = false;       // true <-> destroy throws RTE (always)
517         private boolean throwOnActivate = false;      // true <-> activate throws RTE (always)
518         private boolean throwOnMake = false;          // true <-> make throws RTE (always)
519         private boolean throwOnValidate= false;       // true <-> validate throws RTE (always)
520         private boolean throwOnPassivate = false;     // true <-> passivate throws RTE (always)
521         private boolean makeNull = false;             // true <-> make returns null
522         public Object makeObject() {
523             if (throwOnMake) {
524                 final int next = counter + 1;
525                 throw new IntegerFactoryException("makeObject", next);
526             } else {
527                 return makeNull? null : new Integer(counter++);
528             }
529         }
530         public void destroyObject(Object obj) {
531             if (throwOnDestroy) {
532                 final Integer integer = (Integer)obj;
533                 throw new IntegerFactoryException("destroyObject", integer.intValue());
534             }
535             destroyed.add(obj);
536         }
537         public boolean validateObject(Object obj) {
538             if (throwOnValidate) {
539                 final Integer integer = (Integer)obj;
540                 throw new IntegerFactoryException("validateObject", integer.intValue());
541             }
542             if (validateSelectively) {
543                 // only odd objects are valid
544                 if(obj instanceof Integer) {
545                     return ((((Integer)obj).intValue() % 2) == 1);
546                 } else {
547                     return false;
548                 }
549             }
550             return true;
551         }
552         public void activateObject(Object obj) {
553             if (throwOnActivate) {
554                 final Integer integer = (Integer)obj;
555                 throw new IntegerFactoryException("activateObject", integer.intValue());
556             }
557         }
558         public void passivateObject(Object obj) { 
559             if (throwOnPassivate) {
560                 final Integer integer = (Integer)obj;
561                 throw new IntegerFactoryException("passivateObject", integer.intValue());
562             }
563             if (passivateSelectively) {
564                 final Integer integer = (Integer)obj;
565                 if (integer.intValue() % 3 == 0) {
566                     throw new IntegerFactoryException("passivateObject", integer.intValue());
567                 }
568             }
569         }
570         public List getDestroyed() {
571             return destroyed;
572         }
573         public void setCounter(int counter) {
574             this.counter = counter;
575         }
576         public void setValidateSelectively(boolean validateSelectively) {
577             this.validateSelectively = validateSelectively;
578         }
579         public void setPassivateSelectively(boolean passivateSelectively) {
580             this.passivateSelectively = passivateSelectively;
581         }
582         public void setThrowOnDestroy(boolean throwOnDestroy) {
583             this.throwOnDestroy = throwOnDestroy;
584         }
585         public void setThrowOnActivate(boolean throwOnActivate) {
586             this.throwOnActivate = throwOnActivate;
587         }
588         public void setThrowOnMake(boolean throwOnMake) {
589             this.throwOnMake = throwOnMake;
590         }
591         public void setThrowOnPassivate(boolean throwOnPassivate) {
592             this.throwOnPassivate = throwOnPassivate;
593         }
594         public void setThrowOnValidate(boolean throwOnValidate) {
595             this.throwOnValidate = throwOnValidate;
596         }
597         public void setMakeNull(boolean makeNull) {
598             this.makeNull = makeNull;
599         }
600     }
601     
602     static class IntegerFactoryException extends RuntimeException {
603         private String type;
604         private int value;
605         public IntegerFactoryException(String type, int value) {
606             super(type + " failed. Value: " + value);
607             this.type = type;
608             this.value = value;
609         }
610         public String getType() {
611             return type;
612         }
613         public int getValue() {
614             return value;
615         }
616     }
617 
618     protected boolean isLifo() {
619         return true;
620     }
621 
622     protected boolean isFifo() {
623         return false;
624     }
625 }
626