Pool implements IPool { public Object take() throws PoolTakeException { if (freeItemsCounter.getAndDecrement() <= 0) { freeItemsCounter.getAndIncrement(); try { throw new PoolTakeException("Reached limit of items for this pool.", new OutOfResourceException(this)); } catch (InvalidArgumentException ex) { throw new PoolTakeException("Reached limit of items for this pool.", ex); } } try { Object result = freeItems.poll(); if (result == null) { result = creationFunction.get(); } return result; } catch (Exception e) { freeItemsCounter.getAndIncrement(); throw new PoolTakeException("Failed to get item", e); } } Pool(final Integer maxItems, final Supplier<Object>  func); Object take(); void put(final Object item); void onAvailable(final IPoorAction action);  }
@Test(expected = PoolTakeException.class) public void Should_getItemsWhenRequired() throws Exception { Pool pool = new Pool(3, Object::new); assertNotNull(pool.take()); assertNotNull(pool.take()); assertNotNull(pool.take()); pool.take(); fail(); }
@Test public void Should_incrementCounterWhenExceptionIsThrown() throws Exception { Supplier func = mock(Supplier.class); when(func.get()).thenThrow(new RuntimeException()).thenReturn(new Object()); Pool pool = new Pool(1, func); try { pool.take(); fail(); } catch (PoolTakeException ignored) {} assertNotNull(pool.take()); }