1 10 11 package org.picocontainer.defaults; 12 13 import junit.framework.Assert; 14 import org.jmock.Mock; 15 import org.jmock.MockObjectTestCase; 16 import org.picocontainer.ComponentMonitor; 17 import org.picocontainer.MutablePicoContainer; 18 import org.picocontainer.PicoContainer; 19 import org.picocontainer.PicoLifecycleException; 20 import org.picocontainer.Startable; 21 import org.picocontainer.monitors.LifecycleComponentMonitor; 22 import org.picocontainer.monitors.LifecycleComponentMonitor.LifecycleFailuresException; 23 import org.picocontainer.testmodel.RecordingLifecycle.FiveTriesToBeMalicious; 24 import org.picocontainer.testmodel.RecordingLifecycle.Four; 25 import org.picocontainer.testmodel.RecordingLifecycle.One; 26 import org.picocontainer.testmodel.RecordingLifecycle.Three; 27 import org.picocontainer.testmodel.RecordingLifecycle.Two; 28 29 import java.lang.reflect.Method ; 30 import java.util.ArrayList ; 31 import java.util.HashMap ; 32 import java.util.List ; 33 34 42 public class DefaultPicoContainerLifecycleTestCase extends MockObjectTestCase { 43 44 45 public void testOrderOfInstantiationShouldBeDependencyOrder() throws Exception { 46 47 DefaultPicoContainer pico = new DefaultPicoContainer(); 48 pico.registerComponentImplementation("recording", StringBuffer .class); 49 pico.registerComponentImplementation(Four.class); 50 pico.registerComponentImplementation(Two.class); 51 pico.registerComponentImplementation(One.class); 52 pico.registerComponentImplementation(Three.class); 53 final List componentInstances = pico.getComponentInstances(); 54 55 assertEquals("Incorrect Order of Instantiation", One.class, componentInstances.get(1).getClass()); 57 assertEquals("Incorrect Order of Instantiation", Two.class, componentInstances.get(2).getClass()); 58 assertEquals("Incorrect Order of Instantiation", Three.class, componentInstances.get(3).getClass()); 59 assertEquals("Incorrect Order of Instantiation", Four.class, componentInstances.get(4).getClass()); 60 } 61 62 public void testOrderOfStartShouldBeDependencyOrderAndStopAndDisposeTheOpposite() throws Exception { 63 DefaultPicoContainer parent = new DefaultPicoContainer(); 64 MutablePicoContainer child = parent.makeChildContainer(); 65 66 parent.registerComponentImplementation("recording", StringBuffer .class); 67 child.registerComponentImplementation(Four.class); 68 parent.registerComponentImplementation(Two.class); 69 parent.registerComponentImplementation(One.class); 70 child.registerComponentImplementation(Three.class); 71 72 parent.start(); 73 parent.stop(); 74 parent.dispose(); 75 76 assertEquals("<One<Two<Three<FourFour>Three>Two>One>!Four!Three!Two!One", 77 parent.getComponentInstance("recording").toString()); 78 } 79 80 81 public void testLifecycleIsIgnoredIfAdaptersAreNotLifecycleManagers() { 82 DefaultPicoContainer parent = new DefaultPicoContainer(new ConstructorInjectionComponentAdapterFactory()); 83 MutablePicoContainer child = parent.makeChildContainer(); 84 85 parent.registerComponentImplementation("recording", StringBuffer .class); 86 child.registerComponentImplementation(Four.class); 87 parent.registerComponentImplementation(Two.class); 88 parent.registerComponentImplementation(One.class); 89 child.registerComponentImplementation(Three.class); 90 91 parent.start(); 92 parent.stop(); 93 parent.dispose(); 94 95 assertEquals("", 96 parent.getComponentInstance("recording").toString()); 97 } 98 99 public void testStartStartShouldFail() throws Exception { 100 DefaultPicoContainer pico = new DefaultPicoContainer(); 101 pico.start(); 102 try { 103 pico.start(); 104 fail("Should have failed"); 105 } catch (IllegalStateException e) { 106 } 108 } 109 110 public void testStartStopStopShouldFail() throws Exception { 111 DefaultPicoContainer pico = new DefaultPicoContainer(); 112 pico.start(); 113 pico.stop(); 114 try { 115 pico.stop(); 116 fail("Should have failed"); 117 } catch (IllegalStateException e) { 118 } 120 } 121 122 public void testStartStopDisposeDisposeShouldFail() throws Exception { 123 DefaultPicoContainer pico = new DefaultPicoContainer(); 124 pico.start(); 125 pico.stop(); 126 pico.dispose(); 127 try { 128 pico.dispose(); 129 fail("Should have barfed"); 130 } catch (IllegalStateException e) { 131 } 133 } 134 135 public static class FooRunnable implements Runnable , Startable { 136 private int runCount; 137 private Thread thread = new Thread (); 138 private boolean interrupted; 139 140 public FooRunnable() { 141 } 142 143 public int runCount() { 144 return runCount; 145 } 146 147 public boolean isInterrupted() { 148 return interrupted; 149 } 150 151 public void start() { 152 thread = new Thread (this); 153 thread.start(); 154 } 155 156 public void stop() { 157 thread.interrupt(); 158 } 159 160 public void run() { 163 runCount++; 164 try { 165 Thread.sleep(10000); 166 } catch (InterruptedException e) { 167 interrupted = true; 168 } 169 } 170 } 171 172 public void testStartStopOfDaemonizedThread() throws Exception { 173 DefaultPicoContainer pico = new DefaultPicoContainer(); 174 pico.registerComponentImplementation(FooRunnable.class); 175 176 pico.getComponentInstances(); 177 pico.start(); 178 Thread.sleep(100); 179 pico.stop(); 180 181 FooRunnable foo = (FooRunnable) pico.getComponentInstance(FooRunnable.class); 182 assertEquals(1, foo.runCount()); 183 pico.start(); 184 Thread.sleep(100); 185 pico.stop(); 186 assertEquals(2, foo.runCount()); 187 } 188 189 public void testGetComponentInstancesOnParentContainerHostedChildContainerDoesntReturnParentAdapter() { 190 MutablePicoContainer parent = new DefaultPicoContainer(); 191 MutablePicoContainer child = parent.makeChildContainer(); 192 assertEquals(0, child.getComponentInstances().size()); 193 } 194 195 public void testComponentsAreStartedBreadthFirstAndStoppedAndDisposedDepthFirst() { 196 MutablePicoContainer parent = new DefaultPicoContainer(); 197 parent.registerComponentImplementation(Two.class); 198 parent.registerComponentImplementation("recording", StringBuffer .class); 199 parent.registerComponentImplementation(One.class); 200 MutablePicoContainer child = parent.makeChildContainer(); 201 child.registerComponentImplementation(Three.class); 202 parent.start(); 203 parent.stop(); 204 parent.dispose(); 205 206 assertEquals("<One<Two<ThreeThree>Two>One>!Three!Two!One", parent.getComponentInstance("recording").toString()); 207 } 208 209 public void testMaliciousComponentCannotExistInAChildContainerAndSeeAnyElementOfContainerHierarchy() { 210 MutablePicoContainer parent = new DefaultPicoContainer(); 211 parent.registerComponentImplementation(Two.class); 212 parent.registerComponentImplementation("recording", StringBuffer .class); 213 parent.registerComponentImplementation(One.class); 214 parent.registerComponentImplementation(Three.class); 215 MutablePicoContainer child = parent.makeChildContainer(); 216 child.registerComponentImplementation(FiveTriesToBeMalicious.class); 217 try { 218 parent.start(); 219 fail("Thrown " + UnsatisfiableDependenciesException.class.getName() + " expected"); 220 } catch ( UnsatisfiableDependenciesException e) { 221 } 223 String recording = parent.getComponentInstance("recording").toString(); 224 assertEquals("<One<Two<Three", recording); 225 try { 226 child.getComponentInstanceOfType(FiveTriesToBeMalicious.class); 227 fail("Thrown " + UnsatisfiableDependenciesException.class.getName() + " expected"); 228 } catch (final UnsatisfiableDependenciesException e) { 229 } 231 recording = parent.getComponentInstance("recording").toString(); 232 assertEquals("<One<Two<Three", recording); } 234 235 236 public static class NotStartable { 237 public void start(){ 238 Assert.fail("start() should not get invoked on NonStartable"); 239 } 240 } 241 242 public void testOnlyStartableComponentsAreStartedOnStart() { 243 MutablePicoContainer pico = new DefaultPicoContainer(); 244 pico.registerComponentImplementation("recording", StringBuffer .class); 245 pico.registerComponentImplementation(One.class); 246 pico.registerComponentImplementation(NotStartable.class); 247 pico.start(); 248 pico.stop(); 249 pico.dispose(); 250 assertEquals("<OneOne>!One", pico.getComponentInstance("recording").toString()); 251 } 252 253 public void testShouldFailOnStartAfterDispose() { 254 MutablePicoContainer pico = new DefaultPicoContainer(); 255 pico.dispose(); 256 try { 257 pico.start(); 258 fail(); 259 } catch (IllegalStateException expected) { 260 } 261 } 262 263 public void testShouldFailOnStopAfterDispose() { 264 MutablePicoContainer pico = new DefaultPicoContainer(); 265 pico.dispose(); 266 try { 267 pico.stop(); 268 fail(); 269 } catch (IllegalStateException expected) { 270 } 271 } 272 273 public void testShouldStackContainersLast() { 274 MutablePicoContainer pico = new DefaultPicoContainer(); 277 pico.registerComponentImplementation(ArrayList .class); 278 pico.registerComponentImplementation(DefaultPicoContainer.class); 279 pico.registerComponentImplementation(HashMap .class); 280 pico.start(); 281 PicoContainer childContainer = (PicoContainer) pico.getComponentInstance(DefaultPicoContainer.class); 282 try { 284 childContainer.start(); 285 fail(); 286 } catch (IllegalStateException e) { 287 } 288 } 289 290 public void testCanSpecifyLifeCycleStrategyForInstanceRegistrationWhenSpecifyingComponentAdapterFactory() 291 throws Exception 292 { 293 LifecycleStrategy strategy = new LifecycleStrategy() { 294 public void start(Object component) { 295 ((StringBuffer )component).append("start>"); 296 } 297 298 public void stop(Object component) { 299 ((StringBuffer )component).append("stop>"); 300 } 301 302 public void dispose(Object component) { 303 ((StringBuffer )component).append("dispose>"); 304 } 305 306 public boolean hasLifecycle(Class type) { 307 return true; 308 } 309 }; 310 MutablePicoContainer pico = new DefaultPicoContainer( new DefaultComponentAdapterFactory(), strategy, null ); 311 312 StringBuffer sb = new StringBuffer (); 313 314 pico.registerComponentInstance(sb); 315 316 pico.start(); 317 pico.stop(); 318 pico.dispose(); 319 320 assertEquals("start>stop>dispose>", sb.toString()); 321 } 322 323 public void testLifeCycleStrategyForInstanceRegistrationPassedToChildContainers() 324 throws Exception 325 { 326 LifecycleStrategy strategy = new LifecycleStrategy() { 327 public void start(Object component) { 328 ((StringBuffer )component).append("start>"); 329 } 330 331 public void stop(Object component) { 332 ((StringBuffer )component).append("stop>"); 333 } 334 335 public void dispose(Object component) { 336 ((StringBuffer )component).append("dispose>"); 337 } 338 339 public boolean hasLifecycle(Class type) { 340 return true; 341 } 342 }; 343 MutablePicoContainer parent = new DefaultPicoContainer(strategy, null); 344 MutablePicoContainer pico = parent.makeChildContainer(); 345 346 StringBuffer sb = new StringBuffer (); 347 348 pico.registerComponentInstance(sb); 349 350 pico.start(); 351 pico.stop(); 352 pico.dispose(); 353 354 assertEquals("start>stop>dispose>", sb.toString()); 355 } 356 357 358 public void testLifecycleDoesNotRecoverWithDefaultComponentMonitor() { 359 360 Mock s1 = mock(Startable.class, "s1"); 361 s1.expects(once()).method("start").will(throwException(new RuntimeException ("I do not want to start myself"))); 362 363 Mock s2 = mock(Startable.class, "s2"); 364 365 DefaultPicoContainer dpc = new DefaultPicoContainer(); 366 dpc.registerComponentInstance("foo", s1.proxy()); 367 dpc.registerComponentInstance("bar", s2.proxy()); 368 try { 369 dpc.start(); 370 fail("PicoLifecylceException expected"); 371 } catch (PicoLifecycleException e) { 372 assertEquals("I do not want to start myself", e.getCause().getMessage()); 373 } 374 dpc.stop(); 375 } 376 377 public void testLifecycleCanRecoverWithCustomComponentMonitor() throws NoSuchMethodException { 378 379 Mock s1 = mock(Startable.class, "s1"); 380 s1.expects(once()).method("start").will(throwException(new RuntimeException ("I do not want to start myself"))); 381 s1.expects(once()).method("stop"); 382 383 Mock s2 = mock(Startable.class, "s2"); 384 s2.expects(once()).method("start"); 385 s2.expects(once()).method("stop"); 386 387 Mock cm = mock(ComponentMonitor.class); 388 389 cm.expects(once()).method("invoking").with(eq(Startable.class.getMethod("start", (Class [])null)), same(s1.proxy())); 391 cm.expects(once()).method("lifecycleInvocationFailed").with(isA(Method .class),same(s1.proxy()), isA(RuntimeException .class) ); 392 cm.expects(once()).method("invoking").with(eq(Startable.class.getMethod("stop", (Class [])null)), same(s1.proxy())); 393 cm.expects(once()).method("invoked").with(eq(Startable.class.getMethod("stop", (Class [])null)), same(s1.proxy()), ANYTHING); 394 395 cm.expects(once()).method("invoking").with(eq(Startable.class.getMethod("start", (Class [])null)), same(s2.proxy())); 397 cm.expects(once()).method("invoked").with(eq(Startable.class.getMethod("start", (Class [])null)), same(s2.proxy()), ANYTHING); 398 cm.expects(once()).method("invoking").with(eq(Startable.class.getMethod("stop", (Class [])null)), same(s2.proxy())); 399 cm.expects(once()).method("invoked").with(eq(Startable.class.getMethod("stop", (Class [])null)), same(s2.proxy()), ANYTHING); 400 401 DefaultPicoContainer dpc = new DefaultPicoContainer((ComponentMonitor) cm.proxy()); 402 dpc.registerComponentInstance("foo", s1.proxy()); 403 dpc.registerComponentInstance("bar", s2.proxy()); 404 dpc.start(); 405 dpc.stop(); 406 } 407 408 public void testLifecycleFailuresCanBePickedUpAfterTheEvent() { 409 410 Mock s1 = mock(Startable.class, "s1"); 411 s1.expects(once()).method("start").will(throwException(new RuntimeException ("I do not want to start myself"))); 412 s1.expects(once()).method("stop"); 413 414 Mock s2 = mock(Startable.class, "s2"); 415 s2.expects(once()).method("start"); 416 s2.expects(once()).method("stop"); 417 418 LifecycleComponentMonitor lifecycleComponentMonitor = new LifecycleComponentMonitor(); 419 420 DefaultPicoContainer dpc = new DefaultPicoContainer(lifecycleComponentMonitor); 421 dpc.registerComponentInstance("foo", s1.proxy()); 422 dpc.registerComponentInstance("bar", s2.proxy()); 423 424 dpc.start(); 425 426 try { 427 lifecycleComponentMonitor.rethrowLifecycleFailuresException(); 428 fail("LifecycleFailuresException expected"); 429 } catch (LifecycleFailuresException e) { 430 dpc.stop(); 431 assertEquals(1, e.getFailures().size()); 432 } 433 434 } 435 436 public void testStartedComponentsCanBeStoppedIfSomeComponentsFailToStart() { 437 438 Mock s1 = mock(Startable.class, "s1"); 439 s1.expects(once()).method("start"); 440 s1.expects(once()).method("stop"); 441 442 Mock s2 = mock(Startable.class, "s2"); 443 s2.expects(once()).method("start").will(throwException(new RuntimeException ("I do not want to start myself"))); 444 446 DefaultPicoContainer dpc = new DefaultPicoContainer(); 447 dpc.registerComponentInstance("foo", s1.proxy()); 448 dpc.registerComponentInstance("bar", s2.proxy()); 449 450 try { 451 dpc.start(); 452 fail("PicoLifecylceException expected"); 453 } catch (RuntimeException e) { 454 dpc.stop(); 455 } 456 457 } 458 459 public void testStartedComponentsCanBeStoppedIfSomeComponentsFailToStartEvenInAPicoHierarchy() { 460 461 Mock s1 = mock(Startable.class, "s1"); 462 s1.expects(once()).method("start"); 463 s1.expects(once()).method("stop"); 464 465 Mock s2 = mock(Startable.class, "s2"); 466 s2.expects(once()).method("start").will(throwException(new RuntimeException ("I do not want to start myself"))); 467 469 DefaultPicoContainer dpc = new DefaultPicoContainer(); 470 dpc.registerComponentInstance("foo", s1.proxy()); 471 dpc.registerComponentInstance("bar", s2.proxy()); 472 dpc.addChildContainer(new DefaultPicoContainer(dpc)); 473 474 try { 475 dpc.start(); 476 fail("PicoLifecylceException expected"); 477 } catch (RuntimeException e) { 478 dpc.stop(); 479 } 480 481 } 482 483 public void testChildContainerIsStoppedWhenStartedIndependentlyOfParent() throws Exception { 484 485 DefaultPicoContainer parent = new DefaultPicoContainer(); 486 487 parent.start(); 488 489 MutablePicoContainer child = parent.makeChildContainer(); 490 491 Mock s1 = mock(Startable.class, "s1"); 492 s1.expects(once()).method("start"); 493 s1.expects(once()).method("stop"); 494 495 child.registerComponentInstance(s1.proxy()); 496 497 child.start(); 498 parent.stop(); 499 500 } 501 } | Popular Tags |