1 5 package org.picocontainer.gems.adapters; 6 7 import com.thoughtworks.proxy.ProxyFactory; 8 import com.thoughtworks.proxy.factory.CglibProxyFactory; 9 import com.thoughtworks.proxy.toys.pool.Poolable; 10 11 import org.picocontainer.ComponentAdapter; 12 import org.picocontainer.LifecycleManager; 13 import org.picocontainer.MutablePicoContainer; 14 import org.picocontainer.defaults.ConstructorInjectionComponentAdapter; 15 import org.picocontainer.defaults.DefaultPicoContainer; 16 import org.picocontainer.tck.AbstractComponentAdapterTestCase; 17 import org.picocontainer.testmodel.RecordingLifecycle; 18 import org.picocontainer.testmodel.SimpleTouchable; 19 import org.picocontainer.testmodel.Touchable; 20 21 import java.io.Serializable ; 22 import java.util.HashSet ; 23 import java.util.Iterator ; 24 import java.util.Set ; 25 26 27 30 public class PoolingComponentAdapterTest extends AbstractComponentAdapterTestCase { 31 32 public static interface Identifiable { 33 int getId(); 34 } 35 36 public static class InstanceCounter implements Identifiable, Serializable { 37 private static int counter = 0; 38 private int id; 39 40 public InstanceCounter() { 41 id = counter++; 42 } 43 44 public int getId() { 45 return id; 46 } 47 48 public boolean equals(Object arg) { 49 return arg instanceof Identifiable && id == ((Identifiable)arg).getId(); 50 } 51 } 52 53 protected void setUp() throws Exception { 54 InstanceCounter.counter = 0; 55 } 56 57 public void testNewIsInstantiatedOnEachRequest() { 58 ComponentAdapter componentAdapter = new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 59 Identifiable.class, InstanceCounter.class)); 60 61 Object borrowed0 = componentAdapter.getComponentInstance(null); 62 Object borrowed1 = componentAdapter.getComponentInstance(null); 63 64 assertNotSame(borrowed0, borrowed1); 65 } 66 67 public void testInstancesCanBeRecycled() { 68 ComponentAdapter componentAdapter = new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 69 Identifiable.class, InstanceCounter.class)); 70 71 Object borrowed0 = componentAdapter.getComponentInstance(null); 72 Object borrowed1 = componentAdapter.getComponentInstance(null); 73 Object borrowed2 = componentAdapter.getComponentInstance(null); 74 75 assertNotSame(borrowed0, borrowed1); 76 assertNotSame(borrowed1, borrowed2); 77 78 borrowed1 = null; 79 System.gc(); 80 81 Identifiable borrowed = (Identifiable)componentAdapter.getComponentInstance(null); 82 assertEquals(1, borrowed.getId()); 83 84 ((Poolable)borrowed).returnInstanceToPool(); 85 86 Object borrowedReloaded = componentAdapter.getComponentInstance(null); 87 assertEquals(borrowed, borrowedReloaded); 88 } 89 90 public void testBlocksWhenExhausted() throws InterruptedException { 91 final ComponentAdapter componentAdapter = new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 92 Identifiable.class, InstanceCounter.class), new PoolingComponentAdapter.DefaultContext() { 93 public int getMaxSize() { 94 return 2; 95 } 96 97 public int getMaxWaitInMilliseconds() { 98 return 3000; 99 } 100 }); 101 102 final Identifiable[] borrowed = new Identifiable[3]; 103 final Throwable [] threadException = new Throwable [2]; 104 105 final StringBuffer order = new StringBuffer (); 106 final Thread returner = new Thread () { 107 public void run() { 108 try { 109 synchronized (this) { 110 notifyAll(); 111 wait(200); } 113 order.append("returner "); 114 ((Poolable)borrowed[0]).returnInstanceToPool(); 115 } catch (Throwable t) { 116 t.printStackTrace(); 117 synchronized (componentAdapter) { 118 componentAdapter.notify(); 119 } 120 threadException[1] = t; 121 } 122 } 123 }; 124 125 borrowed[0] = (Identifiable)componentAdapter.getComponentInstance(null); 126 borrowed[1] = (Identifiable)componentAdapter.getComponentInstance(null); 127 synchronized (returner) { 128 returner.start(); 129 returner.wait(); 130 } 131 132 order.append("main "); 134 borrowed[2] = (Identifiable)componentAdapter.getComponentInstance(null); 135 order.append("main"); 136 137 returner.join(); 138 139 assertNull(threadException[0]); 140 assertNull(threadException[1]); 141 142 assertEquals("main returner main", order.toString()); 143 144 assertEquals(borrowed[0].getId(), borrowed[2].getId()); 145 assertFalse(borrowed[1].getId() == borrowed[2].getId()); 146 } 147 148 public void testTimeoutWhenExhausted() { 149 final ComponentAdapter componentAdapter = new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 150 Identifiable.class, InstanceCounter.class), new PoolingComponentAdapter.DefaultContext() { 151 public int getMaxSize() { 152 return 2; 153 } 154 155 public int getMaxWaitInMilliseconds() { 156 return 250; 157 } 158 }); 159 160 Identifiable borrowed0 = (Identifiable)componentAdapter.getComponentInstance(null); 161 Identifiable borrowed1 = (Identifiable)componentAdapter.getComponentInstance(null); 162 assertNotNull(borrowed0); 163 assertFalse(borrowed0.getId() == borrowed1.getId()); 164 long time = System.currentTimeMillis(); 165 try { 166 componentAdapter.getComponentInstance(null); 167 fail("Thrown " + PoolException.class.getName() + " expected"); 168 } catch (final PoolException e) { 169 assertTrue(e.getMessage().indexOf("Time out") >= 0); 170 assertTrue(System.currentTimeMillis() - time >= 250); 171 } 172 } 173 174 public void testGrowsAlways() { 175 PoolingComponentAdapter componentAdapter = new PoolingComponentAdapter( 176 new ConstructorInjectionComponentAdapter("foo", Object .class), 177 new PoolingComponentAdapter.DefaultContext() { 178 179 public ProxyFactory getProxyFactory() { 180 return new CglibProxyFactory(); 181 } 182 }); 183 184 final Set set = new HashSet (); 185 try { 186 final int max = 5; 187 int i; 188 for (i = 0; i < max; ++i) { 189 assertEquals(i, componentAdapter.size()); 190 final Object object = componentAdapter.getComponentInstance(null); 191 set.add(object); 192 } 193 assertEquals(i, componentAdapter.size()); 194 assertEquals(i, set.size()); 195 196 for (Iterator iter = set.iterator(); iter.hasNext();) { 197 Poolable object = (Poolable)iter.next(); 198 object.returnInstanceToPool(); 199 assertEquals(max, componentAdapter.size()); 200 } 201 202 for (i = 0; i < max; ++i) { 203 assertEquals(max, componentAdapter.size()); 204 final Object object = componentAdapter.getComponentInstance(null); 205 assertNotNull(object); 206 set.add(object); 207 } 208 209 assertEquals(max, set.size()); 210 211 } catch (PoolException e) { 212 fail("This pool should not get exhausted."); 213 } 214 } 215 216 public void testFailsWhenExhausted() { 217 final PoolingComponentAdapter componentAdapter = new PoolingComponentAdapter( 218 new ConstructorInjectionComponentAdapter(Identifiable.class, InstanceCounter.class), 219 new PoolingComponentAdapter.DefaultContext() { 220 public int getMaxSize() { 221 return 2; 222 } 223 }); 224 225 assertEquals(0, componentAdapter.size()); 226 Identifiable borrowed0 = (Identifiable)componentAdapter.getComponentInstance(null); 227 assertEquals(1, componentAdapter.size()); 228 Identifiable borrowed1 = (Identifiable)componentAdapter.getComponentInstance(null); 229 assertEquals(2, componentAdapter.size()); 230 try { 231 componentAdapter.getComponentInstance(null); 232 fail("Expected ExhaustedException, pool shouldn't be able to grow further."); 233 } catch (PoolException e) { 234 assertTrue(e.getMessage().indexOf("exhausted") >= 0); 235 } 236 237 assertFalse(borrowed0.getId() == borrowed1.getId()); 238 } 239 240 public void testInternalGCCall() { 241 ComponentAdapter componentAdapter = new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 242 Identifiable.class, InstanceCounter.class), new PoolingComponentAdapter.DefaultContext() { 243 public int getMaxSize() { 244 return 1; 245 } 246 247 public boolean autostartGC() { 248 return true; 249 } 250 }); 251 252 for (int i = 0; i < 5; i++) { 253 final Identifiable borrowed = (Identifiable)componentAdapter.getComponentInstance(null); 254 assertNotNull(borrowed); 255 assertEquals(0, borrowed.getId()); 256 } 257 } 258 259 267 private ComponentAdapter prepDEF_lifecycleManagerSupport(MutablePicoContainer picoContainer) { 268 picoContainer.registerComponentImplementation(RecordingLifecycle.One.class); 269 return picoContainer.registerComponent(new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 270 RecordingLifecycle.Recorder.class, RecordingLifecycle.Two.class))); 271 } 272 273 public void testDEF_lifecycleManagerSupport() { 274 if ((getComponentAdapterNature() & RESOLVING) > 0) { 275 final Class type = getComponentAdapterType(); 276 if (LifecycleManager.class.isAssignableFrom(type)) { 277 final StringBuffer buffer = new StringBuffer (); 278 final MutablePicoContainer picoContainer = new DefaultPicoContainer( 279 createDefaultComponentAdapterFactory()); 280 picoContainer.registerComponentInstance(buffer); 281 final ComponentAdapter componentAdapter = prepDEF_lifecycleManagerSupport(picoContainer); 282 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 283 assertEquals(0, buffer.length()); 284 picoContainer.start(); 285 picoContainer.stop(); 286 picoContainer.dispose(); 287 assertEquals("<OneOne>!One", buffer.toString()); 289 } 290 } 291 } 292 293 302 private ComponentAdapter prepRES_lifecycleManagerHonorsInstantiationSequence(MutablePicoContainer picoContainer) { 303 picoContainer.registerComponentImplementation(RecordingLifecycle.One.class); 304 return picoContainer.registerComponent(new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 305 RecordingLifecycle.Recorder.class, RecordingLifecycle.Two.class))); 306 } 307 308 public void testRES_lifecycleManagerHonorsInstantiationSequence() { 309 if ((getComponentAdapterNature() & RESOLVING) > 0) { 310 final Class type = getComponentAdapterType(); 311 if (LifecycleManager.class.isAssignableFrom(type)) { 312 final StringBuffer buffer = new StringBuffer (); 313 final MutablePicoContainer picoContainer = new DefaultPicoContainer( 314 createDefaultComponentAdapterFactory()); 315 picoContainer.registerComponentInstance(buffer); 316 final ComponentAdapter componentAdapter = prepRES_lifecycleManagerHonorsInstantiationSequence(picoContainer); 317 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 318 assertEquals(0, buffer.length()); 319 picoContainer.start(); 320 picoContainer.stop(); 321 picoContainer.dispose(); 322 assertEquals("<One<TwoTwo>One>!Two!One", buffer.toString()); 324 } 325 } 326 } 327 328 330 protected Class getComponentAdapterType() { 331 return PoolingComponentAdapter.class; 332 } 333 334 protected int getComponentAdapterNature() { 335 return super.getComponentAdapterNature() & ~(INSTANTIATING | RESOLVING | VERIFYING); 336 } 337 338 private ComponentAdapter createPoolOfTouchables() { 339 return new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 340 Touchable.class, SimpleTouchable.class)); 341 } 342 343 protected ComponentAdapter prepDEF_verifyWithoutDependencyWorks(MutablePicoContainer picoContainer) { 344 return createPoolOfTouchables(); 345 } 346 347 protected ComponentAdapter prepDEF_verifyDoesNotInstantiate(MutablePicoContainer picoContainer) { 348 return createPoolOfTouchables(); 349 } 350 351 protected ComponentAdapter prepDEF_visitable() { 352 return createPoolOfTouchables(); 353 } 354 355 private ComponentAdapter createSerializable() { 356 return new PoolingComponentAdapter(new ConstructorInjectionComponentAdapter( 357 Identifiable.class, InstanceCounter.class)); 358 } 359 360 protected ComponentAdapter prepSER_isSerializable(MutablePicoContainer picoContainer) { 361 return createSerializable(); 362 } 363 364 protected ComponentAdapter prepSER_isXStreamSerializable(MutablePicoContainer picoContainer) { 365 return createSerializable(); 366 } 367 368 } 369 | Popular Tags |