001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.pool.impl; 019 020 import java.util.ArrayList; 021 import java.util.BitSet; 022 import java.util.List; 023 import java.util.NoSuchElementException; 024 025 import org.apache.commons.pool.ObjectPool; 026 import org.apache.commons.pool.PoolableObjectFactory; 027 import org.apache.commons.pool.TestBaseObjectPool; 028 029 /** 030 * @author Rodney Waldhoff 031 * @author Dirk Verbeeck 032 * @author Sandy McArthur 033 * @version $Revision: 960644 $ $Date: 2010-07-05 10:15:07 -0700 (Mon, 05 Jul 2010) $ 034 */ 035 public class TestStackObjectPool extends TestBaseObjectPool { 036 public TestStackObjectPool(String testName) { 037 super(testName); 038 } 039 040 protected ObjectPool makeEmptyPool(int mincap) { 041 return new StackObjectPool(new SimpleFactory()); 042 } 043 044 protected ObjectPool makeEmptyPool(final PoolableObjectFactory factory) { 045 return new StackObjectPool(factory); 046 } 047 048 protected Object getNthObject(int n) { 049 return String.valueOf(n); 050 } 051 052 public void testIdleCap() throws Exception { 053 ObjectPool pool = makeEmptyPool(8); 054 Object[] active = new Object[100]; 055 for(int i=0;i<100;i++) { 056 active[i] = pool.borrowObject(); 057 } 058 assertEquals(100,pool.getNumActive()); 059 assertEquals(0,pool.getNumIdle()); 060 for(int i=0;i<100;i++) { 061 pool.returnObject(active[i]); 062 assertEquals(99 - i,pool.getNumActive()); 063 assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle()); 064 } 065 } 066 067 /** 068 * @deprecated - to be removed in pool 2.0 069 */ 070 public void testPoolWithNullFactory() throws Exception { 071 ObjectPool pool = new StackObjectPool(10); 072 for(int i=0;i<10;i++) { 073 pool.returnObject(new Integer(i)); 074 } 075 for(int j=0;j<3;j++) { 076 Integer[] borrowed = new Integer[10]; 077 BitSet found = new BitSet(); 078 for(int i=0;i<10;i++) { 079 borrowed[i] = (Integer)(pool.borrowObject()); 080 assertNotNull(borrowed); 081 assertTrue(!found.get(borrowed[i].intValue())); 082 found.set(borrowed[i].intValue()); 083 } 084 for(int i=0;i<10;i++) { 085 pool.returnObject(borrowed[i]); 086 } 087 } 088 pool.invalidateObject(pool.borrowObject()); 089 pool.invalidateObject(pool.borrowObject()); 090 pool.clear(); 091 } 092 093 /** 094 * @deprecated - to be removed in pool 2.0 095 */ 096 public void testBorrowFromEmptyPoolWithNullFactory() throws Exception { 097 ObjectPool pool = new StackObjectPool(); 098 try { 099 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