001 /***************************************************************************** 002 * Copyright (C) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Original code by * 009 *****************************************************************************/ 010 package org.picocontainer.defaults; 011 012 import java.awt.event.ActionEvent; 013 import java.awt.event.ActionListener; 014 import java.lang.reflect.Constructor; 015 import java.lang.reflect.InvocationTargetException; 016 import java.util.HashMap; 017 import java.util.Map; 018 019 import org.jmock.Mock; 020 import org.jmock.core.Constraint; 021 import org.picocontainer.ComponentAdapter; 022 import org.picocontainer.ComponentMonitor; 023 import org.picocontainer.MutablePicoContainer; 024 import org.picocontainer.Parameter; 025 import org.picocontainer.PicoInitializationException; 026 import org.picocontainer.PicoIntrospectionException; 027 import org.picocontainer.PicoRegistrationException; 028 import org.picocontainer.tck.AbstractComponentAdapterTestCase; 029 import org.picocontainer.testmodel.DependsOnTouchable; 030 import org.picocontainer.testmodel.NullLifecycle; 031 import org.picocontainer.testmodel.SimpleTouchable; 032 import org.picocontainer.testmodel.Touchable; 033 034 035 public class ConstructorInjectionComponentAdapterTestCase extends AbstractComponentAdapterTestCase { 036 037 protected Class getComponentAdapterType() { 038 return ConstructorInjectionComponentAdapter.class; 039 } 040 041 protected ComponentAdapter prepDEF_verifyWithoutDependencyWorks(MutablePicoContainer picoContainer) { 042 return new ConstructorInjectionComponentAdapter("foo", A.class); 043 } 044 045 public static class A { 046 public A() { 047 fail("verification should not instantiate"); 048 } 049 } 050 051 public static class B { 052 public B(A a) { 053 fail("verification should not instantiate"); 054 } 055 } 056 057 protected ComponentAdapter prepDEF_verifyDoesNotInstantiate(MutablePicoContainer picoContainer) { 058 picoContainer.registerComponentImplementation(A.class); 059 return new ConstructorInjectionComponentAdapter(B.class, B.class); 060 } 061 062 protected ComponentAdapter prepDEF_visitable() { 063 return new ConstructorInjectionComponentAdapter("bar", B.class, new Parameter[]{ComponentParameter.DEFAULT}); 064 } 065 066 protected ComponentAdapter prepDEF_isAbleToTakeParameters(MutablePicoContainer picoContainer) { 067 picoContainer.registerComponentImplementation(SimpleTouchable.class); 068 return new ConstructorInjectionComponentAdapter( 069 NamedDependsOnTouchable.class, NamedDependsOnTouchable.class, new Parameter[]{ 070 ComponentParameter.DEFAULT, new ConstantParameter("Name")}); 071 } 072 073 protected ComponentAdapter prepSER_isSerializable(MutablePicoContainer picoContainer) { 074 return new ConstructorInjectionComponentAdapter(SimpleTouchable.class, SimpleTouchable.class); 075 } 076 077 protected ComponentAdapter prepSER_isXStreamSerializable(final MutablePicoContainer picoContainer) { 078 return prepSER_isSerializable(picoContainer); 079 } 080 081 public static class NamedDependsOnTouchable extends DependsOnTouchable { 082 public NamedDependsOnTouchable(Touchable t, String name) { 083 super(t); 084 } 085 } 086 087 protected ComponentAdapter prepVER_verificationFails(MutablePicoContainer picoContainer) { 088 return new ConstructorInjectionComponentAdapter(DependsOnTouchable.class, DependsOnTouchable.class); 089 } 090 091 protected ComponentAdapter prepINS_createsNewInstances(MutablePicoContainer picoContainer) { 092 return new ConstructorInjectionComponentAdapter(SimpleTouchable.class, SimpleTouchable.class); 093 } 094 095 public static class Erroneous { 096 public Erroneous() { 097 throw new VerifyError("test"); 098 } 099 } 100 101 protected ComponentAdapter prepINS_errorIsRethrown(MutablePicoContainer picoContainer) { 102 return new ConstructorInjectionComponentAdapter(Erroneous.class, Erroneous.class); 103 } 104 105 public static class RuntimeThrowing { 106 public RuntimeThrowing() { 107 throw new RuntimeException("test"); 108 } 109 } 110 111 protected ComponentAdapter prepINS_runtimeExceptionIsRethrown(MutablePicoContainer picoContainer) { 112 return new ConstructorInjectionComponentAdapter(RuntimeThrowing.class, RuntimeThrowing.class); 113 } 114 115 public static class NormalExceptionThrowing { 116 public NormalExceptionThrowing() throws Exception { 117 throw new Exception("test"); 118 } 119 } 120 121 protected ComponentAdapter prepINS_normalExceptionIsRethrownInsidePicoInvocationTargetInitializationException( 122 MutablePicoContainer picoContainer) { 123 return new ConstructorInjectionComponentAdapter(NormalExceptionThrowing.class, NormalExceptionThrowing.class); 124 } 125 126 protected ComponentAdapter prepRES_dependenciesAreResolved(MutablePicoContainer picoContainer) { 127 picoContainer.registerComponentImplementation(SimpleTouchable.class); 128 return new ConstructorInjectionComponentAdapter(DependsOnTouchable.class, DependsOnTouchable.class); 129 } 130 131 public static class C1 { 132 public C1(C2 c2) { 133 fail("verification should not instantiate"); 134 } 135 } 136 137 public static class C2 { 138 public C2(C1 c1) { 139 fail("verification should not instantiate"); 140 } 141 } 142 143 protected ComponentAdapter prepRES_failingVerificationWithCyclicDependencyException(MutablePicoContainer picoContainer) { 144 final ComponentAdapter componentAdapter = new ConstructorInjectionComponentAdapter(C1.class, C1.class); 145 picoContainer.registerComponent(componentAdapter); 146 picoContainer.registerComponentImplementation(C2.class, C2.class); 147 return componentAdapter; 148 } 149 150 protected ComponentAdapter prepRES_failingInstantiationWithCyclicDependencyException(MutablePicoContainer picoContainer) { 151 final ComponentAdapter componentAdapter = new ConstructorInjectionComponentAdapter(C1.class, C1.class); 152 picoContainer.registerComponent(componentAdapter); 153 picoContainer.registerComponentImplementation(C2.class, C2.class); 154 return componentAdapter; 155 } 156 157 public void testNormalExceptionThrownInCtorIsRethrownInsideInvocationTargetExeption() { 158 DefaultPicoContainer picoContainer = new DefaultPicoContainer(); 159 picoContainer.registerComponentImplementation(NormalExceptionThrowing.class); 160 try { 161 picoContainer.getComponentInstance(NormalExceptionThrowing.class); 162 fail(); 163 } catch (PicoInvocationTargetInitializationException e) { 164 assertEquals("test", e.getCause().getMessage()); 165 } 166 } 167 168 public abstract class InstantiationExceptionThrowing { 169 public InstantiationExceptionThrowing() { 170 } 171 } 172 173 public void testInstantiationExceptionThrownInCtorIsRethrownInsideInvocationTargetExeption() { 174 DefaultPicoContainer picoContainer = new DefaultPicoContainer(); 175 try { 176 picoContainer.registerComponentImplementation(InstantiationExceptionThrowing.class); 177 picoContainer.getComponentInstance(InstantiationExceptionThrowing.class); 178 fail(); 179 } catch (NotConcreteRegistrationException e) { 180 } 181 } 182 183 public class IllegalAccessExceptionThrowing { 184 private IllegalAccessExceptionThrowing() { 185 } 186 } 187 188 // TODO test fails currently, since non accessible ctors are filtered out, because of 189 // PICO-201. 190 // Maybe we can activate it again with some kind of SecurityManager & Policy combination? 191 public void XXXtestIllegalAccessExceptionThrownInCtorIsRethrownInsideInvocationTargetExeption() { 192 DefaultPicoContainer picoContainer = new DefaultPicoContainer(); 193 try { 194 picoContainer.registerComponentImplementation(IllegalAccessExceptionThrowing.class); 195 picoContainer.getComponentInstance(IllegalAccessExceptionThrowing.class); 196 fail(); 197 } catch (PicoInitializationException e) { 198 assertTrue(e.getCause().getMessage().indexOf(IllegalAccessExceptionThrowing.class.getName()) > 0); 199 } 200 } 201 202 public void testPicoInitializationExceptionThrownBecauseOfFilteredConstructors() { 203 DefaultPicoContainer picoContainer = new DefaultPicoContainer(); 204 try { 205 picoContainer.registerComponentImplementation(IllegalAccessExceptionThrowing.class); 206 picoContainer.getComponentInstance(IllegalAccessExceptionThrowing.class); 207 fail(); 208 } catch (PicoInitializationException e) { 209 assertTrue(e.getMessage().indexOf(IllegalAccessExceptionThrowing.class.getName()) > 0); 210 } 211 } 212 213 public void testRegisterAbstractShouldFail() throws PicoRegistrationException, PicoIntrospectionException { 214 MutablePicoContainer pico = new DefaultPicoContainer(); 215 216 try { 217 pico.registerComponentImplementation(Runnable.class); 218 fail("Shouldn't be allowed to register abstract classes or interfaces."); 219 } catch (NotConcreteRegistrationException e) { 220 assertEquals(Runnable.class, e.getComponentImplementation()); 221 assertTrue(e.getMessage().indexOf(Runnable.class.getName()) > 0); 222 } 223 } 224 225 private static class Private { 226 private Private() { 227 } 228 } 229 230 private static class NotYourBusiness { 231 private NotYourBusiness(Private aPrivate) { 232 assertNotNull(aPrivate); 233 } 234 } 235 236 // http://jira.codehaus.org/browse/PICO-189 237 public void testShouldBeAbleToInstantiateNonPublicClassesWithNonPublicConstructors() { 238 DefaultPicoContainer pico = new DefaultPicoContainer(new ConstructorInjectionComponentAdapterFactory(true)); 239 pico.registerComponentImplementation(Private.class); 240 pico.registerComponentImplementation(NotYourBusiness.class); 241 assertNotNull(pico.getComponentInstance(NotYourBusiness.class)); 242 } 243 244 static public class Component201 { 245 public Component201(final String s) { 246 } 247 248 protected Component201(final Integer i, final Boolean b) { 249 fail("Wrong constructor taken."); 250 } 251 } 252 253 // http://jira.codehaus.org/browse/PICO-201 254 public void testShouldNotConsiderNonPublicConstructors() { 255 DefaultPicoContainer pico = new DefaultPicoContainer(); 256 pico.registerComponentImplementation(Component201.class); 257 pico.registerComponentInstance(new Integer(2)); 258 pico.registerComponentInstance(new Boolean(true)); 259 pico.registerComponentInstance("Hello"); 260 assertNotNull(pico.getComponentInstance(Component201.class)); 261 } 262 263 public void testMonitoringHappensBeforeAndAfterInstantiation() throws NoSuchMethodException { 264 Mock monitor = mock(ComponentMonitor.class); 265 Constructor emptyHashMapCtor = HashMap.class.getConstructor(new Class[0]); 266 monitor.expects(once()).method("instantiating").with(eq(emptyHashMapCtor)); 267 Constraint durationIsGreaterThanOrEqualToZero = new Constraint() { 268 public boolean eval(Object o) { 269 Long duration = (Long)o; 270 return 0 <= duration.longValue(); 271 } 272 273 public StringBuffer describeTo(StringBuffer stringBuffer) { 274 return stringBuffer.append("The endTime wasn't after the startTime"); 275 } 276 }; 277 Constraint isAHashMapThatWozCreated = new Constraint() { 278 public boolean eval(Object o) { 279 return o instanceof HashMap; 280 } 281 282 public StringBuffer describeTo(StringBuffer stringBuffer) { 283 return stringBuffer.append("Should have been a hashmap"); 284 } 285 }; 286 287 Constraint injectedIsEmptyArray = new Constraint() { 288 public boolean eval(Object o) { 289 Object[] injected = (Object[])o; 290 return 0 == injected.length; 291 } 292 293 public StringBuffer describeTo(StringBuffer stringBuffer) { 294 return stringBuffer.append("Should have had nothing injected into it"); 295 } 296 }; 297 298 monitor.expects(once()).method("instantiated").with(eq(emptyHashMapCtor), isAHashMapThatWozCreated, injectedIsEmptyArray, durationIsGreaterThanOrEqualToZero); 299 ConstructorInjectionComponentAdapter cica = new ConstructorInjectionComponentAdapter( 300 Map.class, HashMap.class, new Parameter[0], false, (ComponentMonitor)monitor.proxy()); 301 cica.getComponentInstance(null); 302 } 303 304 public void testMonitoringHappensBeforeAndOnFailOfImpossibleComponentsInstantiation() throws NoSuchMethodException { 305 Mock monitor = mock(ComponentMonitor.class); 306 Constructor barfingActionListenerCtor = BarfingActionListener.class.getConstructor(new Class[0]); 307 monitor.expects(once()).method("instantiating").with(eq(barfingActionListenerCtor)); 308 309 Constraint isITE = new Constraint() { 310 public boolean eval(Object o) { 311 Exception ex = (Exception)o; 312 return ex instanceof InvocationTargetException; 313 } 314 315 public StringBuffer describeTo(StringBuffer stringBuffer) { 316 return stringBuffer.append("Should have been unable to instantiate"); 317 } 318 }; 319 320 monitor.expects(once()).method("instantiationFailed").with(eq(barfingActionListenerCtor), isITE); 321 ConstructorInjectionComponentAdapter cica = new ConstructorInjectionComponentAdapter( 322 ActionListener.class, BarfingActionListener.class, new Parameter[0], false, (ComponentMonitor)monitor.proxy()); 323 try { 324 cica.getComponentInstance(null); 325 fail("Should barf"); 326 } catch (RuntimeException e) { 327 assertEquals("Barf!", e.getMessage()); 328 } 329 } 330 331 private static class BarfingActionListener implements ActionListener { 332 public BarfingActionListener() { 333 throw new RuntimeException("Barf!"); 334 } 335 336 public void actionPerformed(ActionEvent e) { 337 } 338 } 339 340 public void testCustomLifecycleCanBeInjected() throws NoSuchMethodException { 341 RecordingLifecycleStrategy strategy = new RecordingLifecycleStrategy(new StringBuffer()); 342 ConstructorInjectionComponentAdapter cica = new ConstructorInjectionComponentAdapter( 343 NullLifecycle.class, NullLifecycle.class, new Parameter[0], false, 344 new DelegatingComponentMonitor(), strategy); 345 Touchable touchable = new SimpleTouchable(); 346 cica.start(touchable); 347 cica.stop(touchable); 348 cica.dispose(touchable); 349 assertEquals("<start<stop<dispose", strategy.recording()); 350 } 351 }