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 Aslak Hellesoy and Paul Hammant * 009 *****************************************************************************/ 010 011 package org.picocontainer.script.xml; 012 013 import static org.junit.Assert.assertEquals; 014 import static org.junit.Assert.assertFalse; 015 import static org.junit.Assert.assertNotNull; 016 import static org.junit.Assert.assertNull; 017 import static org.junit.Assert.assertNotSame; 018 import static org.junit.Assert.assertSame; 019 import static org.junit.Assert.assertTrue; 020 import static org.junit.Assert.fail; 021 022 import java.io.File; 023 import java.io.IOException; 024 import java.io.Reader; 025 import java.io.StringReader; 026 import java.io.StringWriter; 027 import java.io.Writer; 028 import java.text.SimpleDateFormat; 029 import java.util.Date; 030 import java.util.Map; 031 import java.util.Properties; 032 import java.util.Collection; 033 034 import javax.swing.JButton; 035 036 import org.junit.Ignore; 037 import org.junit.Test; 038 import org.picocontainer.ComponentAdapter; 039 import org.picocontainer.ComponentFactory; 040 import org.picocontainer.DefaultPicoContainer; 041 import org.picocontainer.MutablePicoContainer; 042 import org.picocontainer.PicoBuilder; 043 import org.picocontainer.PicoContainer; 044 import org.picocontainer.PicoException; 045 import org.picocontainer.ComponentMonitor; 046 import org.picocontainer.LifecycleStrategy; 047 import org.picocontainer.Parameter; 048 import org.picocontainer.PicoCompositionException; 049 import org.picocontainer.classname.DefaultClassLoadingPicoContainer; 050 import org.picocontainer.behaviors.AbstractBehaviorFactory; 051 import org.picocontainer.behaviors.Caching; 052 import org.picocontainer.behaviors.Locked; 053 import org.picocontainer.behaviors.Cached; 054 import org.picocontainer.containers.EmptyPicoContainer; 055 import org.picocontainer.injectors.AdaptingInjection; 056 import org.picocontainer.injectors.ConstructorInjection; 057 import org.picocontainer.injectors.ConstructorInjector; 058 import org.picocontainer.injectors.SetterInjection; 059 import org.picocontainer.injectors.SetterInjector; 060 import org.picocontainer.lifecycle.StartableLifecycleStrategy; 061 import org.picocontainer.monitors.NullComponentMonitor; 062 import org.picocontainer.monitors.WriterComponentMonitor; 063 import org.picocontainer.script.AbstractScriptedContainerBuilderTestCase; 064 import org.picocontainer.script.ScriptedPicoContainerMarkupException; 065 import org.picocontainer.script.TestHelper; 066 import org.picocontainer.script.testmodel.CustomerEntityImpl; 067 import org.picocontainer.script.testmodel.DefaultWebServerConfig; 068 import org.picocontainer.script.testmodel.Entity; 069 import org.picocontainer.script.testmodel.ListSupport; 070 import org.picocontainer.script.testmodel.MapSupport; 071 import org.picocontainer.script.testmodel.OrderEntityImpl; 072 import org.picocontainer.script.testmodel.WebServerConfig; 073 import org.picocontainer.script.testmodel.WebServerConfigComp; 074 import org.picocontainer.script.xml.XMLComponentInstanceFactory; 075 import org.picocontainer.script.xml.XMLContainerBuilder; 076 import org.picocontainer.testmodel.SimpleTouchable; 077 import org.picocontainer.testmodel.Touchable; 078 import org.w3c.dom.Element; 079 import org.xml.sax.SAXException; 080 081 import com.thoughtworks.xstream.XStream; 082 083 /** 084 * @author Paul Hammant 085 * @author Aslak Hellesøy 086 * @author Jeppe Cramon 087 * @author Mauro Talevi 088 */ 089 public final class XMLContainerBuilderTestCase extends AbstractScriptedContainerBuilderTestCase { 090 091 //TODO some tests for XMLContainerBuilder that use a classloader that is retrieved at testtime. 092 // i.e. not a programatic consequence of this.getClass().getClassLoader() 093 094 @Test public void testCreateSimpleContainer() { 095 Reader script = new StringReader("" + 096 "<container>" + 097 " <component-implementation class='java.lang.StringBuffer'/>" + 098 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 099 " <component-implementation key='org.picocontainer.script.testmodel.WebServer' class='org.picocontainer.script.testmodel.WebServerImpl'/>" + 100 "</container>"); 101 102 PicoContainer pico = buildContainer(script); 103 assertEquals(3, pico.getComponents().size()); 104 assertNotNull(pico.getComponent(StringBuffer.class)); 105 assertNotNull(pico.getComponent(DefaultWebServerConfig.class)); 106 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServer")); 107 } 108 109 @Test public void testCreateSimpleContainerWithExplicitKeysAndParameters() { 110 Reader script = new StringReader("" + 111 "<container>" + 112 " <component-implementation key='aBuffer' class='java.lang.StringBuffer'/>" + 113 " <component-implementation key='org.picocontainer.script.testmodel.WebServerConfig' class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 114 " <component-implementation key='org.picocontainer.script.testmodel.WebServer' class='org.picocontainer.script.testmodel.WebServerImpl'>" + 115 " <parameter key='org.picocontainer.script.testmodel.WebServerConfig'/>" + 116 " <parameter key='aBuffer'/>" + 117 " </component-implementation>" + 118 "</container>"); 119 120 PicoContainer pico = buildContainer(script); 121 assertEquals(3, pico.getComponents().size()); 122 assertNotNull(pico.getComponent("aBuffer")); 123 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServerConfig")); 124 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServer")); 125 } 126 127 @Test public void testCreateSimpleContainerWithExplicitKeysAndImplicitParameter() { 128 Reader script = new StringReader("" + 129 "<container>" + 130 " <component-implementation key='aBuffer' class='java.lang.StringBuffer'/>" + 131 " <component-implementation key='org.picocontainer.script.testmodel.WebServerConfig' class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 132 " <component-implementation key='org.picocontainer.script.testmodel.WebServer' class='org.picocontainer.script.testmodel.WebServerImpl'>" + 133 " <parameter/>" + 134 " <parameter key='aBuffer'/>" + 135 " </component-implementation>" + 136 "</container>"); 137 138 PicoContainer pico = buildContainer(script); 139 assertEquals(3, pico.getComponents().size()); 140 assertNotNull(pico.getComponent("aBuffer")); 141 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServerConfig")); 142 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServer")); 143 } 144 145 @Test public void testNonParameterElementsAreIgnoredInComponentImplementation() { 146 Reader script = new StringReader("" + 147 "<container>" + 148 " <component-implementation key='aBuffer' class='java.lang.StringBuffer'/>" + 149 " <component-implementation key='org.picocontainer.script.testmodel.WebServerConfig' class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 150 " <component-implementation key='org.picocontainer.script.testmodel.WebServer' class='org.picocontainer.script.testmodel.WebServerImpl'>" + 151 " <parameter key='org.picocontainer.script.testmodel.WebServerConfig'/>" + 152 " <parameter key='aBuffer'/>" + 153 " <any-old-stuff/>" + 154 " </component-implementation>" + 155 "</container>"); 156 157 PicoContainer pico = buildContainer(script); 158 assertEquals(3, pico.getComponents().size()); 159 assertNotNull(pico.getComponent("aBuffer")); 160 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServerConfig")); 161 assertNotNull(pico.getComponent("org.picocontainer.script.testmodel.WebServer")); 162 } 163 164 @Test public void testContainerCanHostAChild() { 165 Reader script = new StringReader("" + 166 "<container>" + 167 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 168 " <component-implementation class='java.lang.StringBuffer'/>" + 169 " <container>" + 170 " <component-implementation key='org.picocontainer.script.testmodel.WebServer' class='org.picocontainer.script.testmodel.WebServerImpl'/>" + 171 " </container>" + 172 "</container>"); 173 174 PicoContainer pico = buildContainer(script); 175 assertNotNull(pico.getComponent(DefaultWebServerConfig.class)); 176 177 StringBuffer sb = pico.getComponent(StringBuffer.class); 178 assertTrue(sb.toString().indexOf("-WebServerImpl") != -1); 179 } 180 181 @Test public void testClassLoaderHierarchy() throws IOException { 182 File testCompJar = TestHelper.getTestCompJarFile(); 183 File testCompJar2 = new File(testCompJar.getParentFile(), "TestComp2.jar"); 184 File notStartableJar = new File(testCompJar.getParentFile(), "NotStartable.jar"); 185 186 assertTrue(testCompJar.isFile()); 187 assertTrue(testCompJar2.isFile()); 188 189 Reader script = new StringReader("" + 190 "<container>" + 191 " <classpath>" + 192 " <element file='" + testCompJar.getCanonicalPath() + "'>" + 193 " <grant classname='java.io.FilePermission' context='*' value='read' />" + 194 " </element>" + 195 " </classpath>" + 196 " <component-implementation key='foo' class='TestComp'/>" + 197 " <container>" + 198 " <classpath>" + 199 " <element file='" + testCompJar2.getCanonicalPath() + "'/>" + 200 " <element file='" + notStartableJar.getCanonicalPath() + "'/>" + 201 " </classpath>" + 202 " <component-implementation key='bar' class='TestComp2'/>" + 203 " <component-implementation key='phony' class='NotStartable'/>" + 204 " </container>" + 205 " <component-implementation class='java.lang.StringBuffer'/>" + 206 "</container>"); 207 208 PicoContainer pico = buildContainer(script); 209 Object fooTestComp = pico.getComponent("foo"); 210 assertNotNull("Container should have a 'foo' component", fooTestComp); 211 212 StringBuffer sb = pico.getComponent(StringBuffer.class); 213 assertTrue("Container should have instantiated a 'TestComp2' component because it is Startable", sb.toString().indexOf("-TestComp2") != -1); 214 // We are using the DefaultLifecycleManager, which only instantiates Startable components, and not non-Startable components. 215 assertTrue("Container should NOT have instantiated a 'NotStartable' component because it is NOT Startable", sb.toString().indexOf("-NotStartable") == -1); 216 } 217 218 @Test public void testUnknownclassThrowsPicoContainerMarkupException() { 219 try { 220 Reader script = new StringReader("" + 221 "<container>" + 222 " <component-implementation class='FFFoo'/>" + 223 "</container>"); 224 buildContainer(script); 225 fail(); 226 } catch (ScriptedPicoContainerMarkupException expected) { 227 assertTrue(expected.getCause() instanceof ClassNotFoundException); 228 } 229 } 230 231 @Test public void testNoImplementationClassThrowsPicoContainerMarkupException() { 232 Reader script = new StringReader("" + 233 "<container>" + 234 " <component-implementation/>" + 235 "</container>"); 236 try { 237 buildContainer(script); 238 } catch (ScriptedPicoContainerMarkupException expected) { 239 assertEquals("'class' attribute not specified for component-implementation", expected.getMessage()); 240 } 241 } 242 243 @Test public void testConstantParameterWithNoChildElementThrowsPicoContainerMarkupException() { 244 Reader script = new StringReader("" + 245 "<container>" + 246 " <component-implementation class='org.picocontainer.script.xml.TestBeanComposer'>" + 247 " <parameter>" + 248 " </parameter>" + 249 " </component-implementation>" + 250 "</container>"); 251 252 try { 253 buildContainer(script); 254 } catch (ScriptedPicoContainerMarkupException e) { 255 assertEquals("parameter needs a child element", e.getMessage()); 256 } 257 } 258 259 @Test public void testEmptyScriptDoesNotThrowsEmptyCompositionException() { 260 Reader script = new StringReader("<container/>"); 261 buildContainer(script); 262 } 263 264 @Test public void testCreateContainerFromScriptThrowsSAXException() { 265 Reader script = new StringReader("" + 266 "<container component-adapter-factory='" + ConstructorInjection.class.getName() + "'>" + 267 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 268 "<container>"); // open instead of close 269 try { 270 buildContainer(script); 271 } catch (ScriptedPicoContainerMarkupException e) { 272 assertTrue("SAXException", e.getCause() instanceof SAXException); 273 } 274 } 275 276 @Test public void testCreateContainerFromNullScriptThrowsNullPointerException() { 277 Reader script = null; 278 try { 279 buildContainer(script); 280 fail("NullPointerException expected"); 281 } catch (NullPointerException expected) { 282 } 283 } 284 285 @Test public void testShouldThrowExceptionForNonExistantCafClass() { 286 Reader script = new StringReader("" + 287 "<container component-adapter-factory='org.picocontainer.script.SomeInexistantFactory'>" + 288 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 289 "</container>"); 290 try { 291 buildContainer(script); 292 fail(); 293 } catch (ScriptedPicoContainerMarkupException expected) { 294 assertTrue("Message of exception does not contain missing class", expected.getMessage().indexOf("org.picocontainer.script.SomeInexistantFactory") > 0); 295 } 296 } 297 298 @Test public void testComponentInstanceWithNoChildElementThrowsPicoContainerMarkupException() { 299 Reader script = new StringReader("" + 300 "<container>" + 301 " <component-instance>" + 302 " </component-instance>" + 303 "</container>"); 304 305 try { 306 buildContainer(script); 307 fail(); 308 } catch (ScriptedPicoContainerMarkupException expected) { 309 assertEquals("component-instance needs a child element", expected.getMessage()); 310 } 311 } 312 313 @Test public void testComponentInstanceWithFactoryCanBeUsed() { 314 Reader script = new StringReader("" + 315 "<container>" + 316 " <component-instance factory='org.picocontainer.script.xml.XMLContainerBuilderTestCase$TestFactory'>" + 317 " <config-or-whatever/>" + 318 " </component-instance>" + 319 "</container>"); 320 321 PicoContainer pico = buildContainer(script); 322 Object instance = pico.getComponents().get(0); 323 assertNotNull(instance); 324 assertTrue(instance instanceof String); 325 assertEquals("Hello", instance.toString()); 326 } 327 328 @Test public void testComponentInstanceWithDefaultFactory() { 329 Reader script = new StringReader("" + 330 "<container>" + 331 " <component-instance>" + 332 " <org.picocontainer.script.xml.TestBean>" + 333 " <foo>10</foo>" + 334 " <bar>hello</bar>" + 335 " </org.picocontainer.script.xml.TestBean>" + 336 " </component-instance>" + 337 "</container>"); 338 339 PicoContainer pico = buildContainer(script); 340 Object instance = pico.getComponents().get(0); 341 assertNotNull(instance); 342 assertTrue(instance instanceof TestBean); 343 assertEquals(10, ((TestBean) instance).getFoo()); 344 assertEquals("hello", ((TestBean) instance).getBar()); 345 } 346 347 @Test public void testComponentInstanceWithBeanFactory() { 348 Reader script = new StringReader("" + 349 "<container>" + 350 " <component-instance factory='org.picocontainer.script.xml.BeanComponentInstanceFactory'>" + 351 " <org.picocontainer.script.xml.TestBean>" + 352 " <foo>10</foo>" + 353 " <bar>hello</bar>" + 354 " </org.picocontainer.script.xml.TestBean>" + 355 " </component-instance>" + 356 "</container>"); 357 358 PicoContainer pico = buildContainer(script); 359 Object instance = pico.getComponents().get(0); 360 assertNotNull(instance); 361 assertTrue(instance instanceof TestBean); 362 assertEquals(10, ((TestBean) instance).getFoo()); 363 assertEquals("hello", ((TestBean) instance).getBar()); 364 } 365 366 @Test public void testComponentInstanceWithBeanFactoryAndInstanceThatIsDefinedInContainer() { 367 Reader script = new StringReader("" + 368 "<container>" + 369 " <component-instance key='date' factory='org.picocontainer.script.xml.BeanComponentInstanceFactory'>" + 370 " <java.util.Date>" + 371 " <time>0</time>" + 372 " </java.util.Date>" + 373 " </component-instance>" + 374 " <component-instance factory='org.picocontainer.script.xml.BeanComponentInstanceFactory'>" + 375 " <java.text.SimpleDateFormat>" + 376 " <lenient>false</lenient>" + 377 " <date name='2DigitYearStart'>date</date>" + 378 " </java.text.SimpleDateFormat>" + 379 " </component-instance>" + 380 "</container>"); 381 382 PicoContainer pico = buildContainer(script); 383 Object instance = pico.getComponent(SimpleDateFormat.class); 384 assertNotNull(instance); 385 assertTrue(instance instanceof SimpleDateFormat); 386 SimpleDateFormat format = ((SimpleDateFormat) instance); 387 assertFalse(format.isLenient()); 388 assertEquals(new Date(0), format.get2DigitYearStart()); 389 } 390 391 @Test public void testComponentInstanceWithKey() { 392 Reader script = new StringReader("" + 393 "<container>" + 394 " <component-instance key='aString'>" + 395 " <string>Hello</string>" + 396 " </component-instance>" + 397 "" + 398 " <component-instance key='aLong'>" + 399 " <long>22</long>" + 400 " </component-instance>" + 401 "" + 402 " <component-instance key='aButton'>" + 403 " <javax.swing.JButton>" + 404 " <text>Hello</text>" + 405 " <alignmentX>0.88</alignmentX>" + 406 " </javax.swing.JButton>" + 407 " </component-instance>" + 408 "</container>"); 409 410 PicoContainer pico = buildContainer(script); 411 assertEquals("Hello", pico.getComponent("aString")); 412 assertEquals((long)22, pico.getComponent("aLong")); 413 JButton button = (JButton) pico.getComponent("aButton"); 414 assertEquals("Hello", button.getText()); 415 assertEquals(0.88, button.getAlignmentX(), 0.01); 416 } 417 418 @Test public void testComponentInstanceWithClassKey() { 419 Reader script = new StringReader("" + 420 "<container>" + 421 " <component-instance class-name-key='java.util.Map' factory='org.picocontainer.script.xml.XStreamComponentInstanceFactory'>" + 422 " <properties>" + 423 " <property name='foo' value='bar'/>" + 424 " </properties>" + 425 " </component-instance>" + 426 "</container>"); 427 428 PicoContainer pico = buildContainer(script); 429 Map<?,?> map = pico.getComponent(Map.class); 430 assertNotNull(map); 431 assertEquals("bar", map.get("foo")); 432 } 433 434 @Test public void testComponentInstanceWithFactoryAndKey() { 435 Reader script = new StringReader("" + 436 "<container>" + 437 " <component-instance factory='org.picocontainer.script.xml.XMLContainerBuilderTestCase$TestFactory'" + 438 " key='aKey'>" + 439 " <config-or-whatever/>" + 440 " </component-instance>" + 441 "</container>"); 442 443 PicoContainer pico = buildContainer(script); 444 Object instance = pico.getComponent("aKey"); 445 assertNotNull(instance); 446 assertTrue(instance instanceof String); 447 assertEquals("Hello", instance.toString()); 448 } 449 450 @Test public void testComponentInstanceWithContainerFactoryAndKey() { 451 Reader script = new StringReader("" + 452 "<container component-instance-factory='org.picocontainer.script.xml.XMLContainerBuilderTestCase$ContainerTestFactory'>" + 453 " <component-instance factory='org.picocontainer.script.xml.XMLContainerBuilderTestCase$TestFactory'" + 454 " key='firstKey'>" + 455 " <config-or-whatever/>" + 456 " </component-instance>" + 457 " <component-instance key='secondKey'>" + 458 " <config-or-whatever/>" + 459 " </component-instance>" + 460 "</container>"); 461 462 PicoContainer pico = buildContainer(script); 463 Object first = pico.getComponent("firstKey"); 464 assertNotNull(first); 465 assertTrue(first instanceof String); 466 assertEquals("Hello", first.toString()); 467 Object second = pico.getComponent("secondKey"); 468 assertNotNull(second); 469 assertTrue(second instanceof String); 470 assertEquals("ContainerHello", second.toString()); 471 } 472 473 public static class TestFactory implements XMLComponentInstanceFactory { 474 public Object makeInstance(PicoContainer pico, Element elem, ClassLoader classLoader) { 475 return "Hello"; 476 } 477 } 478 479 public static class ContainerTestFactory implements XMLComponentInstanceFactory { 480 public Object makeInstance(PicoContainer pico, Element elem, ClassLoader classLoader) { 481 return "ContainerHello"; 482 } 483 } 484 485 @Test public void testInstantiationOfComponentsWithParams() { 486 Reader script = new StringReader("" + 487 "<container>" + 488 " <component-implementation class='org.picocontainer.script.testmodel.WebServerConfigComp'>" + 489 " <parameter><string>localhost</string></parameter>" + 490 " <parameter><int>8080</int></parameter>" + 491 " </component-implementation>" + 492 " <component-implementation key='org.picocontainer.script.testmodel.WebServer' class='org.picocontainer.script.testmodel.WebServerImpl'/>" + 493 "</container>"); 494 PicoContainer pico = buildContainer(script); 495 assertNotNull(pico.getComponent(WebServerConfigComp.class)); 496 WebServerConfigComp config = pico.getComponent(WebServerConfigComp.class); 497 assertEquals("localhost", config.getHost()); 498 assertEquals(8080, config.getPort()); 499 } 500 501 @Test public void testInstantiationOfComponentsWithParameterInstancesOfSameComponent() { 502 Reader script = new StringReader("" + 503 "<container>" + 504 " <component-implementation class='org.picocontainer.script.xml.TestBeanComposer'>" + 505 " <parameter>" + 506 " <org.picocontainer.script.xml.TestBean>" + 507 " <foo>10</foo>" + 508 " <bar>hello1</bar>" + 509 " </org.picocontainer.script.xml.TestBean>" + 510 " </parameter>" + 511 " <parameter>" + 512 " <org.picocontainer.script.xml.TestBean>" + 513 " <foo>10</foo>" + 514 " <bar>hello2</bar>" + 515 " </org.picocontainer.script.xml.TestBean>" + 516 " </parameter>" + 517 " </component-implementation>" + 518 "</container>"); 519 PicoContainer pico = buildContainer(script); 520 assertNotNull(pico.getComponent(TestBeanComposer.class)); 521 TestBeanComposer composer = pico.getComponent(TestBeanComposer.class); 522 assertEquals("bean1", "hello1", composer.getBean1().getBar()); 523 assertEquals("bean2", "hello2", composer.getBean2().getBar()); 524 } 525 526 @Test public void testInstantiationOfComponentsWithParameterInstancesOfSameComponentAndBeanFactory() { 527 Reader script = new StringReader("" + 528 "<container>" + 529 " <component-implementation class='org.picocontainer.script.xml.TestBeanComposer'>" + 530 " <parameter factory='org.picocontainer.script.xml.BeanComponentInstanceFactory'>" + 531 " <org.picocontainer.script.xml.TestBean>" + 532 " <foo>10</foo>" + 533 " <bar>hello1</bar>" + 534 " </org.picocontainer.script.xml.TestBean>" + 535 " </parameter>" + 536 " <parameter factory='org.picocontainer.script.xml.BeanComponentInstanceFactory'>" + 537 " <org.picocontainer.script.xml.TestBean>" + 538 " <foo>10</foo>" + 539 " <bar>hello2</bar>" + 540 " </org.picocontainer.script.xml.TestBean>" + 541 " </parameter>" + 542 " </component-implementation>" + 543 "</container>"); 544 PicoContainer pico = buildContainer(script); 545 assertNotNull(pico.getComponent(TestBeanComposer.class)); 546 TestBeanComposer composer = pico.getComponent(TestBeanComposer.class); 547 assertEquals("bean1", "hello1", composer.getBean1().getBar()); 548 assertEquals("bean2", "hello2", composer.getBean2().getBar()); 549 } 550 551 @Test public void testInstantiationOfComponentsWithParameterKeys() { 552 Reader script = new StringReader("" + 553 "<container>" + 554 " <component-instance key='bean1'>" + 555 " <org.picocontainer.script.xml.TestBean>" + 556 " <foo>10</foo>" + 557 " <bar>hello1</bar>" + 558 " </org.picocontainer.script.xml.TestBean>" + 559 " </component-instance>" + 560 " <component-instance key='bean2'>" + 561 " <org.picocontainer.script.xml.TestBean>" + 562 " <foo>10</foo>" + 563 " <bar>hello2</bar>" + 564 " </org.picocontainer.script.xml.TestBean>" + 565 " </component-instance>" + 566 " <component-implementation class='org.picocontainer.script.xml.TestBeanComposer'>" + 567 " <parameter key='bean1'/>" + 568 " <parameter key='bean2'/>" + 569 " </component-implementation>" + 570 "</container>"); 571 PicoContainer pico = buildContainer(script); 572 assertNotNull(pico.getComponent(TestBeanComposer.class)); 573 TestBeanComposer composer = pico.getComponent(TestBeanComposer.class); 574 assertEquals("bean1", "hello1", composer.getBean1().getBar()); 575 assertEquals("bean2", "hello2", composer.getBean2().getBar()); 576 } 577 578 @Test public void testInstantiationOfComponentsWithComponentAdapter() { 579 Reader script = new StringReader("" + 580 "<container>" + 581 " <component-instance key='bean1'>" + 582 " <org.picocontainer.script.xml.TestBean>" + 583 " <foo>10</foo>" + 584 " <bar>hello1</bar>" + 585 " </org.picocontainer.script.xml.TestBean>" + 586 " </component-instance>" + 587 " <component-instance key='bean2'>" + 588 " <org.picocontainer.script.xml.TestBean>" + 589 " <foo>10</foo>" + 590 " <bar>hello2</bar>" + 591 " </org.picocontainer.script.xml.TestBean>" + 592 " </component-instance>" + 593 " <component-adapter key='beanKey' class='org.picocontainer.script.xml.TestBeanComposer'>" + 594 " <parameter key='bean1'/>" + 595 " <parameter key='bean2'/>" + 596 " </component-adapter>" + 597 "</container>"); 598 PicoContainer pico = buildContainer(script); 599 assertNotNull(pico.getComponent("beanKey")); 600 TestBeanComposer composer = (TestBeanComposer) pico.getComponent("beanKey"); 601 assertEquals("bean1", "hello1", composer.getBean1().getBar()); 602 assertEquals("bean2", "hello2", composer.getBean2().getBar()); 603 } 604 605 @Test public void testComponentAdapterWithSpecifiedFactory() throws IOException { 606 Reader script = new StringReader("" + 607 "<container>" + 608 " <component-instance key='bean1'>" + 609 " <org.picocontainer.script.xml.TestBean>" + 610 " <foo>10</foo>" + 611 " <bar>hello1</bar>" + 612 " </org.picocontainer.script.xml.TestBean>" + 613 " </component-instance>" + 614 " <component-instance key='bean2'>" + 615 " <org.picocontainer.script.xml.TestBean>" + 616 " <foo>10</foo>" + 617 " <bar>hello2</bar>" + 618 " </org.picocontainer.script.xml.TestBean>" + 619 " </component-instance>" + 620 " <component-adapter key='beanKey' class='org.picocontainer.script.xml.TestBeanComposer'" + 621 " factory='" + AdaptingInjection.class.getName() + "'>" + 622 " <parameter key='bean1'/>" + 623 " <parameter key='bean2'/>" + 624 " </component-adapter>" + 625 "</container>"); 626 MutablePicoContainer pico = (MutablePicoContainer)buildContainer(script); 627 628 629 assertNotNull(pico.getComponent("beanKey")); 630 TestBeanComposer composer = (TestBeanComposer) pico.getComponent("beanKey"); 631 assertEquals("bean1", "hello1", composer.getBean1().getBar()); 632 assertEquals("bean2", "hello2", composer.getBean2().getBar()); 633 } 634 635 @Test public void testComponentAdapterWithNoKeyUsesTypeAsKey() { 636 Reader script = new StringReader("" + 637 "<container>" + 638 " <component-adapter class='org.picocontainer.script.xml.TestBeanComposer'/>" + 639 "</container>"); 640 PicoContainer pico = buildContainer(script); 641 ComponentAdapter<?> adapter = pico.getComponentAdapters().iterator().next(); 642 assertSame(TestBeanComposer.class, adapter.getComponentImplementation()); 643 } 644 645 @Test public void testComponentAdapterWithNoClassThrowsPicoContainerMarkupException() { 646 Reader script = new StringReader("" + 647 "<container>" + 648 " <component-adapter key='beanKey'/> " + 649 "</container>"); 650 try { 651 buildContainer(script); 652 fail(); 653 } catch (ScriptedPicoContainerMarkupException expected) { 654 assertEquals("'class' attribute not specified for component-adapter", expected.getMessage()); 655 } 656 } 657 658 @Test public void testCachingCanBeUnsetAtContainerLevel() { 659 Reader script = new StringReader("" + 660 "<container caching='false'>" + 661 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 662 "</container>"); 663 664 PicoContainer pico = buildContainer(script); 665 Object wsc1 = pico.getComponent(WebServerConfig.class); 666 Object wsc2 = pico.getComponent(WebServerConfig.class); 667 668 assertNotSame(wsc1, wsc2); 669 } 670 671 @Test public void testCachingCanBeSetRedunadantlyAtContainerLevel() { 672 Reader script = new StringReader("" + 673 "<container caching='true'>" + 674 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 675 "</container>"); 676 677 PicoContainer pico = buildContainer(script); 678 Object wsc1 = pico.getComponent(WebServerConfig.class); 679 Object wsc2 = pico.getComponent(WebServerConfig.class); 680 681 assertSame(wsc1, wsc2); 682 } 683 684 @Test public void testCustomInjectionFactory() throws IOException { 685 Reader script = new StringReader("" + 686 "<container component-adapter-factory='" + SetterInjection.class.getName() + "'>" + 687 "</container>"); 688 689 MutablePicoContainer pico = (MutablePicoContainer) buildContainer(script); 690 691 pico.addComponent(String.class); 692 693 Collection<ComponentAdapter<?>> foo = pico.getComponentAdapters(); 694 assertEquals(1, foo.size()); 695 ComponentAdapter o = (ComponentAdapter) foo.toArray()[0]; 696 assertTrue(o instanceof Cached); 697 o = o.findAdapterOfType(SetterInjector.class); 698 assertNotNull(o); 699 assertTrue(o instanceof SetterInjector); 700 701 } 702 703 704 @Test public void testComponentMonitorCanBeSpecified() { 705 Reader script = new StringReader("" + 706 "<container component-monitor='" + StaticWriterComponentMonitor.class.getName() + "'>" + 707 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 708 "</container>"); 709 710 PicoContainer pico = buildContainer(script); 711 pico.getComponent(WebServerConfig.class); 712 assertTrue(StaticWriterComponentMonitor.WRITER.toString().length() > 0); 713 } 714 715 @Test public void testComponentMonitorCanBeSpecifiedIfCAFIsSpecified() { 716 Reader script = new StringReader("" + 717 "<container component-adapter-factory='" + AdaptingInjection.class.getName() + 718 "' component-monitor='" + StaticWriterComponentMonitor.class.getName() + "'>" + 719 " <component-implementation class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 720 "</container>"); 721 722 PicoContainer pico = buildContainer(script); 723 pico.getComponent(WebServerConfig.class); 724 assertTrue(StaticWriterComponentMonitor.WRITER.toString().length() > 0); 725 } 726 727 @Test public void testAdaptersAlsoUseBehaviorFactory() { 728 Reader script = new StringReader("" + 729 "<container>" + 730 " <component-adapter-factory class='org.picocontainer.injectors.ConstructorInjection' key='factory'/>" + 731 " <component-adapter class='org.picocontainer.script.testmodel.DefaultWebServerConfig' factory='factory'/>" + 732 "</container>"); 733 PicoContainer pico = buildContainer(script); 734 WebServerConfig cfg1 = pico.getComponent(WebServerConfig.class); 735 WebServerConfig cfg2 = pico.getComponent(WebServerConfig.class); 736 assertNotSame("Instances for components registered with a CICA must not be the same", cfg1, cfg2); 737 } 738 739 740 @SuppressWarnings("serial") 741 public static class MyComponentFactory extends ConstructorInjection { 742 public MyComponentFactory() { 743 super(); 744 } 745 } 746 @SuppressWarnings("serial") 747 public static class MyComponentFactory2 extends AbstractBehaviorFactory { 748 public MyComponentFactory2(ComponentFactory delegate) { 749 wrap(delegate); 750 } 751 } 752 @SuppressWarnings("serial") 753 public static class MyComponentFactory3 extends AbstractBehaviorFactory { 754 public MyComponentFactory3(ComponentFactory delegate) { 755 wrap(delegate); 756 } 757 } 758 759 public void BROKEN_testNestedCAFLooksRightinXml() { 760 Reader script = new StringReader("" + 761 "<container>" + 762 " <component-adapter-factory class='"+ MyComponentFactory3.class.getName()+"' key='factory'>" + 763 " <component-adapter-factory class='"+ MyComponentFactory2.class.getName()+"'>" + 764 " <component-adapter-factory class='"+ MyComponentFactory.class.getName()+"'/>" + 765 " </component-adapter-factory>" + 766 " </component-adapter-factory>" + 767 "</container>"); 768 PicoContainer pico = buildContainer(script); 769 770 String xml = new XStream().toXML(pico).replace('\"','\''); 771 772 assertEquals("<org.picocontainer.classname.DefaultClassLoadingPicoContainer>\n" + 773 " <namedChildContainers/>\n" + 774 " <delegate class='org.picocontainer.DefaultPicoContainer'>\n" + 775 " <componentKeyToAdapterCache/>\n" + 776 " <componentFactory class='"+ MyComponentFactory3.class.getName()+"'>\n" + 777 " <delegate class='"+ MyComponentFactory2.class.getName()+"'>\n" + 778 " <delegate class='"+ MyComponentFactory.class.getName()+"'>\n" + 779 " </delegate>\n" + 780 " </delegate>\n" + 781 " </componentFactory>\n" + 782 " <children/>\n" + 783 " <componentAdapters/>\n" + 784 " <orderedComponentAdapters/>\n" + 785 " <started>true</started>\n" + 786 " <disposed>false</disposed>\n" + 787 " <childrenStarted/>\n" + 788 " <lifecycleStrategy class='org.picocontainer.lifecycle.StartableLifecycleStrategy'>\n" + 789 " <componentMonitor class='org.picocontainer.monitors.NullComponentMonitor'/>\n" + 790 " </lifecycleStrategy>\n" + 791 " <componentCharacteristic class='org.picocontainer.DefaultPicoContainer$1'>\n" + 792 " <outer-class reference='../..'/>\n" + 793 " <props/>\n" + 794 " </componentCharacteristic>\n" + 795 " <componentMonitor class='org.picocontainer.monitors.NullComponentMonitor' reference='../lifecycleStrategy/componentMonitor'/>\n" + 796 " </delegate>\n" + 797 "</org.picocontainer.classname.DefaultClassLoadingPicoContainer>", xml); 798 799 // This test suggests that testComponentCanUsePredefinedNestedCAF() is not testing what it hopes to test 800 } 801 802 public static class Hello { 803 } 804 805 @Test 806 public void testComponentCanUsePredefinedNestedCAF() { 807 Reader script = new StringReader("" + 808 "<container>" + 809 " <component-adapter-factory class='org.picocontainer.behaviors.ImplementationHiding' key='factory'>" + 810 " <component-adapter-factory class='"+ MyComponentFactory.class.getName()+"'/>" + 811 " </component-adapter-factory>" + 812 " <component-adapter class-name-key='org.picocontainer.script.testmodel.WebServerConfig' class='org.picocontainer.script.testmodel.DefaultWebServerConfig' factory='factory'/>" + 813 " <component-implementation class='" + Hello.class.getName() + "'/>" + 814 "</container>"); 815 PicoContainer pico = buildContainer(script); 816 WebServerConfig cfg1 = pico.getComponent(WebServerConfig.class); 817 WebServerConfig cfg2 = pico.getComponent(WebServerConfig.class); 818 assertNotSame("Instances for components registered with a CICA must not be the same", cfg1, cfg2); 819 assertFalse("Instance exposes only interface", cfg1 instanceof DefaultWebServerConfig); 820 Hello hello = pico.getComponent(Hello.class); 821 assertNotNull(hello); 822 } 823 824 @Test public void testChainOfWrappedComponents() { 825 826 Reader script = new StringReader("" + 827 "<container>\n" + 828 " <component-implementation key='wrapped' class='"+SimpleTouchable.class.getName()+"'/>" + 829 " <component-implementation class-name-key=\'"+Touchable.class.getName()+"\' class='"+WrapsTouchable.class.getName()+"'/>" + 830 "</container>"); 831 832 PicoContainer pico = buildContainer(script); 833 834 // decorators are fairly dirty - they replace a very select implementation in this TestCase. 835 assertNotNull(pico.getComponent(Touchable.class)); 836 } 837 838 @Test 839 public void testInheritanceOfBehaviorsFromParentContainer() { 840 Reader comparison = new StringReader("" + 841 "<container inheritBehaviors=\"false\">\n" + 842 " <component class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 843 "</container>" 844 ); 845 846 MutablePicoContainer parent = new PicoBuilder().withLocking().build(); 847 PicoContainer comparisonPico = buildContainer(new XMLContainerBuilder(comparison, getClass().getClassLoader()), parent, "SOME_SCOPE"); 848 //Verify not locking by default 849 //assertTrue(comparisonPico.getComponent(DefaultWebServerConfig.class) != comparisonPico.getComponent(DefaultWebServerConfig.class)); 850 assertNull(comparisonPico.getComponentAdapter(DefaultWebServerConfig.class).findAdapterOfType(Locked.class)); 851 852 //Verify parent caching propagates to child. 853 Reader script = new StringReader("" + 854 "<container inheritBehaviors=\"true\">\n" + 855 " <component class='org.picocontainer.script.testmodel.DefaultWebServerConfig'/>" + 856 "</container>" 857 ); 858 859 parent = new PicoBuilder().withLocking().build(); 860 PicoContainer pico = buildContainer(new XMLContainerBuilder(script, getClass().getClassLoader()), parent, "SOME_SCOPE"); 861 862 assertNotNull(pico.getComponentAdapter(DefaultWebServerConfig.class).findAdapterOfType(Locked.class)); 863 } 864 865 866 @Test public void testListSupport() { 867 868 Reader script = new StringReader("" + 869 "<container>\n" + 870 " <component-implementation class='"+ListSupport.class.getName()+"'>" + 871 " <parameter empty-collection='false' component-value-type='"+Entity.class.getName()+"'/>" + 872 " </component-implementation>" + 873 " <component-implementation class=\'"+CustomerEntityImpl.class.getName()+"\'/>" + 874 " <component-implementation class=\'"+OrderEntityImpl.class.getName()+"\'/>" + 875 "</container>"); 876 877 PicoContainer pico = buildContainer(script); 878 879 ListSupport listSupport = pico.getComponent(ListSupport.class); 880 881 assertNotNull(listSupport); 882 assertNotNull(listSupport.getAListOfEntityObjects()); 883 assertEquals(2, listSupport.getAListOfEntityObjects().size()); 884 885 Entity entity1 = listSupport.getAListOfEntityObjects().get(0); 886 Entity entity2 = listSupport.getAListOfEntityObjects().get(1); 887 888 assertNotNull(entity1); 889 assertEquals(CustomerEntityImpl.class, entity1.getClass()); 890 891 assertNotNull(entity2); 892 assertEquals(OrderEntityImpl.class, entity2.getClass()); 893 } 894 895 @Test public void testMapSupport() { 896 897 Reader script = new StringReader("" + 898 "<container>\n" + 899 " <component-implementation class='"+ MapSupport.class.getName()+ "'>" + 900 " <parameter empty-collection='false' component-value-type='"+Entity.class.getName()+"'/>" + 901 " </component-implementation>" + 902 " <component-implementation key='customer' class=\'"+CustomerEntityImpl.class.getName()+"\'/>" + 903 " <component-implementation key='order' class=\'"+OrderEntityImpl.class.getName()+"\'/>" + 904 "</container>"); 905 906 PicoContainer pico = buildContainer(script); 907 908 MapSupport mapSupport = pico.getComponent(MapSupport.class); 909 910 assertNotNull(mapSupport); 911 assertNotNull(mapSupport.getAMapOfEntities()); 912 assertEquals(2, mapSupport.getAMapOfEntities().size()); 913 914 Map<String, Entity> aMapOfEntities = mapSupport.getAMapOfEntities(); 915 916 Entity entity1 = aMapOfEntities.get("customer"); 917 Entity entity2 = aMapOfEntities.get("order"); 918 919 assertNotNull(entity1); 920 assertEquals(CustomerEntityImpl.class, entity1.getClass()); 921 922 assertNotNull(entity2); 923 assertEquals(OrderEntityImpl.class, entity2.getClass()); 924 } 925 926 @Test public void testNoEmptyCollectionWithComponentKeyTypeFailure() { 927 928 Reader script = new StringReader("" + 929 "<container>\n" + 930 " <component-implementation class='"+ MapSupport.class.getName()+ "'>" + 931 " <parameter empty-collection='false' component-key-type='"+Entity.class.getName()+"'/>" + 932 " </component-implementation>" + 933 " <component-implementation key='customer' class=\'"+CustomerEntityImpl.class.getName()+"\'/>" + 934 " <component-implementation key='order' class=\'"+OrderEntityImpl.class.getName()+"\'/>" + 935 "</container>"); 936 937 try { 938 buildContainer(script); 939 fail("Thrown " + PicoException.class.getName() + " expected"); 940 } catch (final PicoException e) { 941 assertTrue(e.getMessage().indexOf("one or both of the emptyCollection")>0); 942 } 943 } 944 945 @Test public void testNoComponentValueTypeWithComponentKeyTypeFailure() { 946 947 Reader script = new StringReader("" + 948 "<container>\n" + 949 " <component-implementation class='"+ MapSupport.class.getName()+ "'>" + 950 " <parameter component-value-type='"+Entity.class.getName()+"' component-key-type='"+Entity.class.getName()+"'/>" + 951 " </component-implementation>" + 952 " <component-implementation key='customer' class=\'"+CustomerEntityImpl.class.getName()+"\'/>" + 953 " <component-implementation key='order' class=\'"+OrderEntityImpl.class.getName()+"\'/>" + 954 "</container>"); 955 956 try { 957 buildContainer(script); 958 fail("Thrown " + PicoException.class.getName() + " expected"); 959 } catch (final PicoException e) { 960 assertTrue(e.getMessage().indexOf("but one or both of the emptyCollection")>0); 961 } 962 } 963 964 @Test public void testNoEmptyCollectionWithComponentValueTypeFailure() { 965 966 Reader script = new StringReader("" + 967 "<container>\n" + 968 " <component-implementation class='"+ MapSupport.class.getName()+ "'>" + 969 " <parameter component-value-type='"+Entity.class.getName()+"'/>" + 970 " </component-implementation>" + 971 " <component-implementation key='customer' class=\'"+CustomerEntityImpl.class.getName()+"\'/>" + 972 " <component-implementation key='order' class=\'"+OrderEntityImpl.class.getName()+"\'/>" + 973 "</container>"); 974 975 try { 976 buildContainer(script); 977 fail("Thrown " + PicoException.class.getName() + " expected"); 978 } catch (final PicoException e) { 979 System.out.println(e); 980 981 assertTrue(e.getMessage().indexOf("but the emptyCollection () was empty or null")>0); 982 } 983 } 984 985 @Test 986 public void testParameterZero() { 987 Reader script = new StringReader("" + 988 "<container>\n" + 989 "<component key='java.util.List' class='java.util.ArrayList'> \n" + 990 " <parameter-zero/>\n" + 991 "</component> \n" + 992 "<component key='java.util.Set' class='java.util.HashSet'> \n" + 993 " <parameter-zero/>\n" + 994 "</component>\n" + 995 "</container>\n" 996 ); 997 PicoContainer pico = buildContainer(script); 998 assertNotNull(pico.getComponent(java.util.List.class)); 999 assertNotNull(pico.getComponent(java.util.Set.class)); 1000 } 1001 1002 private PicoContainer buildContainer(Reader script) { 1003 return buildContainer(new XMLContainerBuilder(script, getClass().getClassLoader()), null, "SOME_SCOPE"); 1004 } 1005 1006 static public final class StaticWriterComponentMonitor extends WriterComponentMonitor { 1007 static final Writer WRITER = new StringWriter(); 1008 1009 public StaticWriterComponentMonitor() { 1010 super(WRITER); 1011 } 1012 1013 } 1014 1015 // TODO: Move this into pico-tck 1016 public static class WrapsTouchable implements Touchable { 1017 private final Touchable wrapped; 1018 1019 public WrapsTouchable(final Touchable wrapped) { 1020 this.wrapped = wrapped; 1021 } 1022 1023 public void touch() { 1024 this.wrapped.touch(); 1025 } 1026 } 1027 } 1028