1 10 package org.picocontainer.tck; 11 12 import com.thoughtworks.xstream.XStream; 13 import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; 14 import com.thoughtworks.xstream.io.xml.XppDriver; 15 16 import junit.framework.Assert; 17 import junit.framework.AssertionFailedError; 18 19 import org.picocontainer.ComponentAdapter; 20 import org.picocontainer.MutablePicoContainer; 21 import org.picocontainer.Parameter; 22 import org.picocontainer.PicoContainer; 23 import org.picocontainer.PicoInitializationException; 24 import org.picocontainer.PicoIntrospectionException; 25 import org.picocontainer.defaults.AbstractPicoVisitor; 26 import org.picocontainer.defaults.ComponentAdapterFactory; 27 import org.picocontainer.defaults.ConstantParameter; 28 import org.picocontainer.defaults.ConstructorInjectionComponentAdapterFactory; 29 import org.picocontainer.defaults.CyclicDependencyException; 30 import org.picocontainer.defaults.DecoratingComponentAdapter; 31 import org.picocontainer.defaults.DefaultComponentAdapterFactory; 32 import org.picocontainer.defaults.DefaultPicoContainer; 33 import org.picocontainer.defaults.LifecycleStrategy; 34 import org.picocontainer.defaults.ObjectReference; 35 import org.picocontainer.defaults.PicoInvocationTargetInitializationException; 36 import org.picocontainer.defaults.SimpleReference; 37 38 import org.jmock.MockObjectTestCase; 39 40 import java.io.ByteArrayInputStream ; 41 import java.io.ByteArrayOutputStream ; 42 import java.io.IOException ; 43 import java.io.ObjectInputStream ; 44 import java.io.ObjectOutputStream ; 45 import java.lang.reflect.Constructor ; 46 import java.util.ArrayList ; 47 import java.util.Collection ; 48 import java.util.HashSet ; 49 import java.util.Iterator ; 50 import java.util.LinkedList ; 51 import java.util.List ; 52 import java.util.Set ; 53 54 55 61 public abstract class AbstractComponentAdapterTestCase extends MockObjectTestCase { 62 63 public static int SERIALIZABLE = 1; 64 public static int VERIFYING = 2; 65 public static int INSTANTIATING = 4; 66 public static int RESOLVING = 8; 67 68 protected abstract Class getComponentAdapterType(); 69 70 protected int getComponentAdapterNature() { 71 return SERIALIZABLE | VERIFYING | INSTANTIATING | RESOLVING; 72 } 73 74 protected ComponentAdapterFactory createDefaultComponentAdapterFactory() { 75 return new DefaultComponentAdapterFactory(); 76 } 77 78 82 89 protected abstract ComponentAdapter prepDEF_verifyWithoutDependencyWorks(MutablePicoContainer picoContainer); 90 91 final public void testDEF_verifyWithoutDependencyWorks() { 92 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 93 final ComponentAdapter componentAdapter = prepDEF_verifyWithoutDependencyWorks(picoContainer); 94 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 95 componentAdapter.verify(picoContainer); 96 } 97 98 105 protected abstract ComponentAdapter prepDEF_verifyDoesNotInstantiate(MutablePicoContainer picoContainer); 106 107 final public void testDEF_verifyDoesNotInstantiate() { 108 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 109 final ComponentAdapter componentAdapter = prepDEF_verifyDoesNotInstantiate(picoContainer); 110 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 111 final ComponentAdapter notInstantiatablecomponentAdapter = new NotInstantiatableComponentAdapter( 112 componentAdapter); 113 final PicoContainer wrappedPicoContainer = wrapComponentInstances( 114 NotInstantiatableComponentAdapter.class, picoContainer, null); 115 notInstantiatablecomponentAdapter.verify(wrappedPicoContainer); 116 } 117 118 124 protected abstract ComponentAdapter prepDEF_visitable(); 125 126 final public void testDEF_visitable() { 127 final ComponentAdapter componentAdapter = prepDEF_visitable(); 128 final Class type = getComponentAdapterType(); 129 assertSame(type, componentAdapter.getClass()); 130 boolean hasParameters = supportsParameters(type); 131 final RecordingVisitor visitor = new RecordingVisitor(); 132 visitor.traverse(componentAdapter); 133 final List visitedElements = new ArrayList (visitor.getVisitedElements()); 134 assertSame(componentAdapter, visitedElements.get(0)); 135 if (hasParameters) { 136 hasParameters = false; 137 for (final Iterator iter = visitedElements.iterator(); iter.hasNext() && !hasParameters;) { 138 hasParameters = Parameter.class.isAssignableFrom(iter.next().getClass()); 139 } 140 assertTrue("ComponentAdapter " + type + " supports parameters, provide some", hasParameters); 141 } 142 } 143 144 152 protected ComponentAdapter prepDEF_isAbleToTakeParameters(MutablePicoContainer picoContainer) { 153 final Class type = getComponentAdapterType(); 154 boolean hasParameters = supportsParameters(type); 155 if (hasParameters) { 156 fail("You have to overwrite this method for a useful test"); 157 } 158 return null; 159 } 160 161 final public void testDEF_isAbleToTakeParameters() { 162 final Class type = getComponentAdapterType(); 163 boolean hasParameters = supportsParameters(type); 164 if (hasParameters) { 165 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 166 final ComponentAdapter componentAdapter = prepDEF_isAbleToTakeParameters(picoContainer); 167 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 168 final RecordingVisitor visitor = new RecordingVisitor(); 169 visitor.traverse(componentAdapter); 170 final List visitedElements = visitor.getVisitedElements(); 171 if (hasParameters) { 172 hasParameters = false; 173 for (final Iterator iter = visitedElements.iterator(); iter.hasNext() && !hasParameters;) { 174 hasParameters = Parameter.class.isAssignableFrom(iter.next().getClass()); 175 } 176 assertTrue("ComponentAdapter " + type + " supports parameters, provide some", hasParameters); 177 } 178 final Object instance = componentAdapter.getComponentInstance(picoContainer); 179 assertNotNull(instance); 180 } 181 } 182 183 187 194 protected ComponentAdapter prepSER_isSerializable(MutablePicoContainer picoContainer) { 195 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 196 } 197 198 final public void testSER_isSerializable() throws IOException , ClassNotFoundException { 199 if ((getComponentAdapterNature() & SERIALIZABLE) > 0) { 200 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 201 final ComponentAdapter componentAdapter = prepSER_isSerializable(picoContainer); 202 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 203 final Object instance = componentAdapter.getComponentInstance(picoContainer); 204 assertNotNull(instance); 205 final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream (); 206 final ObjectOutputStream outputStream = new ObjectOutputStream (byteArrayOutputStream); 207 outputStream.writeObject(componentAdapter); 208 outputStream.close(); 209 final ObjectInputStream inputStream = new ObjectInputStream (new ByteArrayInputStream (byteArrayOutputStream 210 .toByteArray())); 211 final ComponentAdapter serializedComponentAdapter = (ComponentAdapter)inputStream.readObject(); 212 inputStream.close(); 213 assertEquals(componentAdapter.getComponentKey(), serializedComponentAdapter.getComponentKey()); 214 final Object instanceAfterSerialization = serializedComponentAdapter.getComponentInstance(picoContainer); 215 assertNotNull(instanceAfterSerialization); 216 assertSame(instance.getClass(), instanceAfterSerialization.getClass()); 217 } 218 } 219 220 227 protected ComponentAdapter prepSER_isXStreamSerializable(MutablePicoContainer picoContainer) { 228 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 229 } 230 231 final public void testSER_isXStreamSerializableWithPureReflection() { 232 if ((getComponentAdapterNature() & SERIALIZABLE) > 0) { 233 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 234 final ComponentAdapter componentAdapter = prepSER_isXStreamSerializable(picoContainer); 235 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 236 final Object instance = componentAdapter.getComponentInstance(picoContainer); 237 assertNotNull(instance); 238 final XStream xstream = new XStream(new PureJavaReflectionProvider(), new XppDriver()); 239 final String xml = xstream.toXML(componentAdapter); 240 final ComponentAdapter serializedComponentAdapter = (ComponentAdapter)xstream.fromXML(xml); 241 assertEquals(componentAdapter.getComponentKey(), serializedComponentAdapter.getComponentKey()); 242 final Object instanceAfterSerialization = serializedComponentAdapter.getComponentInstance(picoContainer); 243 assertNotNull(instanceAfterSerialization); 244 assertSame(instance.getClass(), instanceAfterSerialization.getClass()); 245 } 246 } 247 248 final public void testSER_isXStreamSerializable() { 249 if ((getComponentAdapterNature() & SERIALIZABLE) > 0) { 250 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 251 final ComponentAdapter componentAdapter = prepSER_isXStreamSerializable(picoContainer); 252 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 253 final Object instance = componentAdapter.getComponentInstance(picoContainer); 254 assertNotNull(instance); 255 final XStream xstream = new XStream(new XppDriver()); 256 final String xml = xstream.toXML(componentAdapter); 257 final ComponentAdapter serializedComponentAdapter = (ComponentAdapter)xstream.fromXML(xml); 258 assertEquals(componentAdapter.getComponentKey(), serializedComponentAdapter.getComponentKey()); 259 final Object instanceAfterSerialization = serializedComponentAdapter.getComponentInstance(picoContainer); 260 assertNotNull(instanceAfterSerialization); 261 assertSame(instance.getClass(), instanceAfterSerialization.getClass()); 262 } 263 } 264 265 269 277 protected ComponentAdapter prepVER_verificationFails(MutablePicoContainer picoContainer) { 278 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 279 } 280 281 final public void testVER_verificationFails() { 282 if ((getComponentAdapterNature() & VERIFYING) > 0) { 283 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 284 final ComponentAdapter componentAdapter = prepVER_verificationFails(picoContainer); 285 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 286 try { 287 componentAdapter.verify(picoContainer); 288 fail("PicoIntrospectionException expected"); 289 } catch (PicoIntrospectionException e) { 290 } catch (Exception e) { 291 fail("PicoIntrospectionException expected, but got " + e.getClass().getName()); 292 } 293 try { 294 componentAdapter.getComponentInstance(picoContainer); 295 fail("PicoInitializationException or PicoIntrospectionException expected"); 296 } catch (PicoInitializationException e) { 297 } catch (PicoIntrospectionException e) { 298 } catch (Exception e) { 299 fail("PicoInitializationException or PicoIntrospectionException expected, but got " 300 + e.getClass().getName()); 301 } 302 } 303 } 304 305 309 316 protected ComponentAdapter prepINS_createsNewInstances(MutablePicoContainer picoContainer) { 317 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 318 } 319 320 final public void testINS_createsNewInstances() { 321 if ((getComponentAdapterNature() & INSTANTIATING) > 0) { 322 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 323 final ComponentAdapter componentAdapter = prepINS_createsNewInstances(picoContainer); 324 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 325 final Object instance = componentAdapter.getComponentInstance(picoContainer); 326 assertNotNull(instance); 327 assertNotSame(instance, componentAdapter.getComponentInstance(picoContainer)); 328 assertSame(instance.getClass(), componentAdapter.getComponentInstance(picoContainer).getClass()); 329 } 330 } 331 332 339 protected ComponentAdapter prepINS_errorIsRethrown(MutablePicoContainer picoContainer) { 340 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 341 } 342 343 final public void testINS_errorIsRethrown() { 344 if ((getComponentAdapterNature() & INSTANTIATING) > 0) { 345 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 346 final ComponentAdapter componentAdapter = prepINS_errorIsRethrown(picoContainer); 347 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 348 try { 349 componentAdapter.getComponentInstance(picoContainer); 350 fail("Thrown Error excpected"); 351 } catch (final Error e) { 352 assertEquals("test", e.getMessage()); 353 } 354 } 355 } 356 357 365 protected ComponentAdapter prepINS_runtimeExceptionIsRethrown(MutablePicoContainer picoContainer) { 366 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 367 } 368 369 final public void testINS_runtimeExceptionIsRethrown() { 370 if ((getComponentAdapterNature() & INSTANTIATING) > 0) { 371 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 372 final ComponentAdapter componentAdapter = prepINS_runtimeExceptionIsRethrown(picoContainer); 373 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 374 try { 375 componentAdapter.getComponentInstance(picoContainer); 376 fail("Thrown RuntimeException excpected"); 377 } catch (final RuntimeException e) { 378 assertEquals("test", e.getMessage()); 379 } 380 } 381 } 382 383 392 protected ComponentAdapter prepINS_normalExceptionIsRethrownInsidePicoInvocationTargetInitializationException( 393 MutablePicoContainer picoContainer) { 394 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 395 } 396 397 final public void testINS_normalExceptionIsRethrownInsidePicoInvocationTargetInitializationException() { 398 if ((getComponentAdapterNature() & INSTANTIATING) > 0) { 399 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 400 final ComponentAdapter componentAdapter = prepINS_normalExceptionIsRethrownInsidePicoInvocationTargetInitializationException(picoContainer); 401 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 402 try { 403 componentAdapter.getComponentInstance(picoContainer); 404 fail("Thrown PicoInvocationTargetInitializationException excpected"); 405 } catch (final PicoInvocationTargetInitializationException e) { 406 assertTrue(e.getMessage().endsWith("test")); 407 assertTrue(e.getCause() instanceof Exception ); 408 } 409 } 410 } 411 412 416 424 protected ComponentAdapter prepRES_dependenciesAreResolved(MutablePicoContainer picoContainer) { 425 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 426 } 427 428 final public void testRES_dependenciesAreResolved() { 429 if ((getComponentAdapterNature() & RESOLVING) > 0) { 430 final List dependencies = new LinkedList (); 431 final Object [] wrapperDependencies = new Object []{dependencies}; 432 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 433 final ComponentAdapter componentAdapter = prepRES_dependenciesAreResolved(picoContainer); 434 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 435 assertFalse(picoContainer.getComponentAdapters().contains(componentAdapter)); 436 final PicoContainer wrappedPicoContainer = wrapComponentInstances( 437 CollectingComponentAdapter.class, picoContainer, wrapperDependencies); 438 final Object instance = componentAdapter.getComponentInstance(wrappedPicoContainer); 439 assertNotNull(instance); 440 assertTrue(dependencies.size() > 0); 441 } 442 } 443 444 452 protected ComponentAdapter prepRES_failingVerificationWithCyclicDependencyException( 453 MutablePicoContainer picoContainer) { 454 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 455 } 456 457 final public void testRES_failingVerificationWithCyclicDependencyException() { 458 if ((getComponentAdapterNature() & RESOLVING) > 0) { 459 final Set cycleInstances = new HashSet (); 460 final ObjectReference cycleCheck = new SimpleReference(); 461 final Object [] wrapperDependencies = new Object []{cycleInstances, cycleCheck}; 462 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 463 final ComponentAdapter componentAdapter = prepRES_failingVerificationWithCyclicDependencyException(picoContainer); 464 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 465 assertTrue(picoContainer.getComponentAdapters().contains(componentAdapter)); 466 final PicoContainer wrappedPicoContainer = wrapComponentInstances( 467 CycleDetectorComponentAdapter.class, picoContainer, wrapperDependencies); 468 try { 469 componentAdapter.verify(wrappedPicoContainer); 470 fail("Thrown PicoVerificationException excpected"); 471 } catch (final CyclicDependencyException cycle) { 472 final Class [] dependencies = cycle.getDependencies(); 473 assertSame(dependencies[0], dependencies[dependencies.length - 1]); 474 } 475 } 476 } 477 478 486 protected ComponentAdapter prepRES_failingInstantiationWithCyclicDependencyException( 487 MutablePicoContainer picoContainer) { 488 throw new AssertionFailedError("You have to overwrite this method for a useful test"); 489 } 490 491 final public void testRES_failingInstantiationWithCyclicDependencyException() { 492 if ((getComponentAdapterNature() & RESOLVING) > 0) { 493 final Set cycleInstances = new HashSet (); 494 final ObjectReference cycleCheck = new SimpleReference(); 495 final Object [] wrapperDependencies = new Object []{cycleInstances, cycleCheck}; 496 final MutablePicoContainer picoContainer = new DefaultPicoContainer(createDefaultComponentAdapterFactory()); 497 final ComponentAdapter componentAdapter = prepRES_failingInstantiationWithCyclicDependencyException(picoContainer); 498 assertSame(getComponentAdapterType(), componentAdapter.getClass()); 499 assertTrue(picoContainer.getComponentAdapters().contains(componentAdapter)); 500 final PicoContainer wrappedPicoContainer = wrapComponentInstances( 501 CycleDetectorComponentAdapter.class, picoContainer, wrapperDependencies); 502 try { 503 componentAdapter.getComponentInstance(wrappedPicoContainer); 504 fail("Thrown CyclicDependencyException excpected"); 505 } catch (final CyclicDependencyException e) { 506 final Class [] dependencies = e.getDependencies(); 507 assertSame(dependencies[0], dependencies[dependencies.length - 1]); 508 } 509 } 510 } 511 512 516 static class RecordingVisitor extends AbstractPicoVisitor { 517 private final List visitedElements = new LinkedList (); 518 519 public void visitContainer(PicoContainer pico) { 520 visitedElements.add(pico); 521 } 522 523 public void visitComponentAdapter(ComponentAdapter componentAdapter) { 524 visitedElements.add(componentAdapter); 525 } 526 527 public void visitParameter(Parameter parameter) { 528 visitedElements.add(parameter); 529 } 530 531 List getVisitedElements() { 532 return visitedElements; 533 } 534 } 535 536 static public class NotInstantiatableComponentAdapter extends DecoratingComponentAdapter { 537 public NotInstantiatableComponentAdapter(final ComponentAdapter delegate) { 538 super(delegate); 539 } 540 541 public Object getComponentInstance(final PicoContainer container) { 542 Assert.fail("Not instantiatable"); 543 return null; 544 } 545 } 546 547 static public class CollectingComponentAdapter extends DecoratingComponentAdapter { 548 final List list; 549 550 public CollectingComponentAdapter(final ComponentAdapter delegate, final List list) { 551 super(delegate); 552 this.list = list; 553 } 554 555 public Object getComponentInstance(final PicoContainer container) { 556 final Object result = super.getComponentInstance(container); 557 list.add(result); 558 return result; 559 } 560 } 561 562 static public class CycleDetectorComponentAdapter extends DecoratingComponentAdapter { 563 private final Set set; 564 private final ObjectReference reference; 565 566 public CycleDetectorComponentAdapter( 567 final ComponentAdapter delegate, final Set set, final ObjectReference reference) { 568 super(delegate); 569 this.set = set; 570 this.reference = reference; 571 } 572 573 public Object getComponentInstance(final PicoContainer container) { 574 if (set.contains(this)) { 575 reference.set(this); 576 } else { 577 set.add(this); 578 } 579 return super.getComponentInstance(container); 580 } 581 } 582 583 public static class RecordingLifecycleStrategy implements LifecycleStrategy { 584 private StringBuffer recorder; 585 586 public RecordingLifecycleStrategy(StringBuffer recorder) { 587 this.recorder = recorder; 588 } 589 590 public void start(Object component) { 591 recorder.append("<start"); 592 } 593 594 public void stop(Object component) { 595 recorder.append("<stop"); 596 } 597 598 public void dispose(Object component) { 599 recorder.append("<dispose"); 600 } 601 602 public boolean hasLifecycle(Class type) { 603 return true; 604 } 605 606 public String recording() { 607 return recorder.toString(); 608 } 609 } 610 611 final protected PicoContainer wrapComponentInstances( 612 final Class decoratingComponentAdapterClass, final PicoContainer picoContainer, 613 final Object [] wrapperDependencies) { 614 assertTrue(DecoratingComponentAdapter.class.isAssignableFrom(decoratingComponentAdapterClass)); 615 final MutablePicoContainer mutablePicoContainer = new DefaultPicoContainer(); 616 final int size = (wrapperDependencies != null ? wrapperDependencies.length : 0) + 1; 617 final Collection allComponentAdapters = picoContainer.getComponentAdapters(); 618 for (final Iterator iter = allComponentAdapters.iterator(); iter.hasNext();) { 619 final Parameter[] parameters = new Parameter[size]; 620 parameters[0] = new ConstantParameter(iter.next()); 621 for (int i = 1; i < parameters.length; i++) { 622 parameters[i] = new ConstantParameter(wrapperDependencies[i - 1]); 623 } 624 final MutablePicoContainer instantiatingPicoContainer = new DefaultPicoContainer( 625 new ConstructorInjectionComponentAdapterFactory()); 626 instantiatingPicoContainer.registerComponentImplementation( 627 "decorator", decoratingComponentAdapterClass, parameters); 628 mutablePicoContainer.registerComponent((ComponentAdapter)instantiatingPicoContainer 629 .getComponentInstance("decorator")); 630 } 631 return mutablePicoContainer; 632 } 633 634 private boolean supportsParameters(final Class type) { 635 boolean hasParameters = false; 636 final Constructor [] constructors = type.getConstructors(); 637 for (int i = 0; i < constructors.length && !hasParameters; i++) { 638 final Constructor constructor = constructors[i]; 639 final Class [] parameterTypes = constructor.getParameterTypes(); 640 for (int j = 0; j < parameterTypes.length; j++) { 641 final Class parameterType = parameterTypes[j]; 642 if (Parameter.class.isAssignableFrom(parameterType) 643 || (parameterType.isArray() && Parameter.class.isAssignableFrom(parameterType 644 .getComponentType()))) { 645 hasParameters = true; 646 break; 647 } 648 } 649 } 650 return hasParameters; 651 } 652 } | Popular Tags |