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