    001    /*****************************************************************************
    002     * Copyright (C) NanoContainer 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.nanocontainer.script.xml;
    012
    013    import java.io.File;
    014    import java.io.IOException;
    015    import java.io.Reader;
    016    import java.io.StringReader;
    017    import java.io.StringWriter;
    018    import java.io.Writer;
    019    import java.text.SimpleDateFormat;
    020    import java.util.ArrayList;
    021    import java.util.Date;
    022    import java.util.Map;
    023    import java.util.Vector;
    024
    025    import javax.swing.JButton;
    026
    027    import org.nanocontainer.script.AbstractScriptedContainerBuilderTestCase;
    028    import org.nanocontainer.script.BarDecoratingPicoContainer;
    029    import org.nanocontainer.script.FooDecoratingPicoContainer;
    030    import org.nanocontainer.script.NanoContainerMarkupException;
    031    import org.nanocontainer.testmodel.DefaultWebServerConfig;
    032    import org.nanocontainer.testmodel.WebServerConfig;
    033    import org.nanocontainer.testmodel.WebServerConfigComp;
    034    import org.picocontainer.ComponentAdapter;
    035    import org.picocontainer.PicoContainer;
    036    import org.picocontainer.PicoException;
    037    import org.picocontainer.defaults.ConstructorInjectionComponentAdapterFactory;
    038    import org.picocontainer.defaults.DefaultComponentAdapterFactory;
    039    import org.picocontainer.monitors.WriterComponentMonitor;
    040    import org.picocontainer.testmodel.SimpleTouchable;
    041    import org.picocontainer.testmodel.Touchable;
    042    import org.w3c.dom.Element;
    043    import org.xml.sax.SAXException;
    044
    045    /**
    046     * @author Paul Hammant
    047     * @author Aslak Helles&oslash;y
    048     * @author Jeppe Cramon
    049     * @author Mauro Talevi
    050     * @version $Revision: 3115 $
    051     */
    052    public class XMLContainerBuilderTestCase extends AbstractScriptedContainerBuilderTestCase {
    053
    054        //TODO some tests for XMLContainerBuilder that use a classloader that is retrieved at testtime.
    055        // i.e. not a programatic consequence of this.getClass().getClassLoader()
    056
    057        public void testCreateSimpleContainer() {
    058            Reader script = new StringReader("" +
    059                    "<container>" +
    060                    "  <component-implementation class='java.lang.StringBuffer'/>" +
    061                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    062                    "  <component-implementation key='org.nanocontainer.testmodel.WebServer' class='org.nanocontainer.testmodel.WebServerImpl'/>" +
    063                    "</container>");
    064
    065            PicoContainer pico = buildContainer(script);
    066            assertEquals(3, pico.getComponentInstances().size());
    067            assertNotNull(pico.getComponentInstance(StringBuffer.class));
    068            assertNotNull(pico.getComponentInstance(DefaultWebServerConfig.class));
    069            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServer"));
    070        }
    071
    072        public void testCreateSimpleContainerWithExplicitKeysAndParameters() {
    073            Reader script = new StringReader("" +
    074                    "<container>" +
    075                    "  <component-implementation key='aBuffer' class='java.lang.StringBuffer'/>" +
    076                    "  <component-implementation key='org.nanocontainer.testmodel.WebServerConfig' class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    077                    "  <component-implementation key='org.nanocontainer.testmodel.WebServer' class='org.nanocontainer.testmodel.WebServerImpl'>" +
    078                    "               <parameter key='org.nanocontainer.testmodel.WebServerConfig'/>" +
    079                    "               <parameter key='aBuffer'/>" +
    080                    "  </component-implementation>" +
    081                    "</container>");
    082
    083            PicoContainer pico = buildContainer(script);
    084            assertEquals(3, pico.getComponentInstances().size());
    085            assertNotNull(pico.getComponentInstance("aBuffer"));
    086            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServerConfig"));
    087            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServer"));
    088        }
    089
    090        public void testCreateSimpleContainerWithExplicitKeysAndImplicitParameter() {
    091            Reader script = new StringReader("" +
    092                    "<container>" +
    093                    "  <component-implementation key='aBuffer' class='java.lang.StringBuffer'/>" +
    094                    "  <component-implementation key='org.nanocontainer.testmodel.WebServerConfig' class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    095                    "  <component-implementation key='org.nanocontainer.testmodel.WebServer' class='org.nanocontainer.testmodel.WebServerImpl'>" +
    096                    "       <parameter/>" +
    097                    "       <parameter key='aBuffer'/>" +
    098                    "  </component-implementation>" +
    099                    "</container>");
    100
    101            PicoContainer pico = buildContainer(script);
    102            assertEquals(3, pico.getComponentInstances().size());
    103            assertNotNull(pico.getComponentInstance("aBuffer"));
    104            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServerConfig"));
    105            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServer"));
    106        }
    107
    108        public void testNonParameterElementsAreIgnoredInComponentImplementation() {
    109            Reader script = new StringReader("" +
    110                    "<container>" +
    111                    "  <component-implementation key='aBuffer' class='java.lang.StringBuffer'/>" +
    112                    "  <component-implementation key='org.nanocontainer.testmodel.WebServerConfig' class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    113                    "  <component-implementation key='org.nanocontainer.testmodel.WebServer' class='org.nanocontainer.testmodel.WebServerImpl'>" +
    114                    "               <parameter key='org.nanocontainer.testmodel.WebServerConfig'/>" +
    115                    "               <parameter key='aBuffer'/>" +
    116                    "               <any-old-stuff/>" +
    117                    "  </component-implementation>" +
    118                    "</container>");
    119
    120            PicoContainer pico = buildContainer(script);
    121            assertEquals(3, pico.getComponentInstances().size());
    122            assertNotNull(pico.getComponentInstance("aBuffer"));
    123            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServerConfig"));
    124            assertNotNull(pico.getComponentInstance("org.nanocontainer.testmodel.WebServer"));
    125        }
    126
    127        public void testContainerCanHostAChild() {
    128            Reader script = new StringReader("" +
    129                    "<container>" +
    130                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    131                    "  <component-implementation class='java.lang.StringBuffer'/>" +
    132                    "  <container>" +
    133                    "    <component-implementation key='org.nanocontainer.testmodel.WebServer' class='org.nanocontainer.testmodel.WebServerImpl'/>" +
    134                    "  </container>" +
    135                    "</container>");
    136
    137            PicoContainer pico = buildContainer(script);
    138            assertNotNull(pico.getComponentInstance(DefaultWebServerConfig.class));
    139
    140            StringBuffer sb = (StringBuffer) pico.getComponentInstance(StringBuffer.class);
    141            assertTrue(sb.toString().indexOf("-WebServerImpl") != -1);
    142        }
    143
    144        public void testClassLoaderHierarchy() throws IOException {
    145            String testcompJarFileName = System.getProperty("testcomp.jar", "src/test-comp/TestComp.jar");
    146            // Paul's path to TestComp. PLEASE do not take out.
    147            //testcompJarFileName = "D:/OSS/PN/java/nanocontainer/src/test-comp/TestComp.jar";
    148            File testCompJar = new File(testcompJarFileName);
    149            assertTrue("The testcomp.jar system property should point to java/nanocontainer/src/test-comp/TestComp.jar", testCompJar.isFile());
    150            File testCompJar2 = new File(testCompJar.getParentFile(), "TestComp2.jar");
    151            File notStartableJar = new File(testCompJar.getParentFile(), "NotStartable.jar");
    152
    153            assertTrue(testCompJar.isFile());
    154            assertTrue(testCompJar2.isFile());
    155
    156            Reader script = new StringReader("" +
    157                    "<container>" +
    158                    "  <classpath>" +
    159                    "    <element file='" + testCompJar.getCanonicalPath() + "'>" +
    160                    "      <grant classname='java.io.FilePermission' context='*' value='read' />" +
    161                    "    </element>" +
    162                    "  </classpath>" +
    163                    "  <component-implementation key='foo' class='TestComp'/>" +
    164                    "  <container>" +
    165                    "    <classpath>" +
    166                    "      <element file='" + testCompJar2.getCanonicalPath() + "'/>" +
    167                    "      <element file='" + notStartableJar.getCanonicalPath() + "'/>" +
    168                    "    </classpath>" +
    169                    "    <component-implementation key='bar' class='TestComp2'/>" +
    170                    "    <component-implementation key='phony' class='NotStartable'/>" +
    171                    "  </container>" +
    172                    "  <component-implementation class='java.lang.StringBuffer'/>" +
    173                    "</container>");
    174
    175            PicoContainer pico = buildContainer(script);
    176            Object fooTestComp = pico.getComponentInstance("foo");
    177            assertNotNull("Container should have a 'foo' component", fooTestComp);
    178
    179            StringBuffer sb = (StringBuffer) pico.getComponentInstance(StringBuffer.class);
    180            assertTrue("Container should have instantiated a 'TestComp2' component because it is Startable", sb.toString().indexOf("-TestComp2") != -1);
    181            // We are using the DefaultLifecycleManager, which only instantiates Startable components, and not non-Startable components.
    182            assertTrue("Container should NOT have instantiated a 'NotStartable' component because it is NOT Startable", sb.toString().indexOf("-NotStartable") == -1);
    183        }
    184
    185        public void testUnknownclassThrowsNanoContainerMarkupException() {
    186            try {
    187                Reader script = new StringReader("" +
    188                        "<container>" +
    189                        "  <component-implementation class='Foo'/>" +
    190                        "</container>");
    191                buildContainer(script);
    192                fail();
    193            } catch (NanoContainerMarkupException expected) {
    194                assertTrue(expected.getCause() instanceof ClassNotFoundException);
    195            }
    196        }
    197
    198        public void testNoImplementationClassThrowsNanoContainerMarkupException() {
    199            Reader script = new StringReader("" +
    200                    "<container>" +
    201                    "  <component-implementation/>" +
    202                    "</container>");
    203            try {
    204                buildContainer(script);
    205            } catch (NanoContainerMarkupException expected) {
    206                assertEquals("'class' attribute not specified for component-implementation", expected.getMessage());
    207            }
    208        }
    209
    210        public void testConstantParameterWithNoChildElementThrowsNanoContainerMarkupException() {
    211            Reader script = new StringReader("" +
    212                    "<container>" +
    213                    "  <component-implementation class='org.nanocontainer.script.xml.TestBeanComposer'>" +
    214                    "               <parameter>" +
    215                    "               </parameter>" +
    216                    "  </component-implementation>" +
    217                    "</container>");
    218
    219            try {
    220                buildContainer(script);
    221            } catch (NanoContainerMarkupException e) {
    222                assertEquals("parameter needs a child element", e.getMessage());
    223            }
    224        }
    225
    226        public void testEmptyScriptDoesNotThrowsEmptyCompositionException() {
    227            Reader script = new StringReader("<container/>");
    228            buildContainer(script);
    229        }
    230
    231        public void testCreateContainerFromScriptThrowsSAXException() {
    232            Reader script = new StringReader("" +
    233                    "<container component-adapter-factory='" + ConstructorInjectionComponentAdapterFactory.class.getName() + "'>" +
    234                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    235                    "<container>");
    236            try {
    237                buildContainer(script);
    238            } catch (NanoContainerMarkupException e) {
    239                assertTrue("SAXException", e.getCause() instanceof SAXException);
    240            }
    241        }
    242
    243        public void testCreateContainerFromNullScriptThrowsNullPointerException() {
    244            Reader script = null;
    245            try {
    246                buildContainer(script);
    247                fail("NullPointerException expected");
    248            } catch (NullPointerException expected) {
    249            }
    250        }
    251
    252        public void testShouldThrowExceptionForNonExistantCafClass() {
    253            Reader script = new StringReader("" +
    254                    "<container component-adapter-factory='org.nanocontainer.SomeInexistantFactory'>" +
    255                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    256                    "</container>");
    257            try {
    258                buildContainer(script);
    259                fail();
    260            } catch (NanoContainerMarkupException expected) {
    261                assertTrue("Message of exception does not contain missing class", expected.getMessage().indexOf("org.nanocontainer.SomeInexistantFactory") > 0);
    262            }
    263        }
    264
    265        public void testComponentInstanceWithNoChildElementThrowsNanoContainerMarkupException() {
    266            Reader script = new StringReader("" +
    267                    "<container>" +
    268                    "  <component-instance>" +
    269                    "  </component-instance>" +
    270                    "</container>");
    271
    272            try {
    273                buildContainer(script);
    274                fail();
    275            } catch (NanoContainerMarkupException expected) {
    276                assertEquals("component-instance needs a child element", expected.getMessage());
    277            }
    278        }
    279
    280        public void testComponentInstanceWithFactoryCanBeUsed() {
    281            Reader script = new StringReader("" +
    282                    "<container>" +
    283                    "  <component-instance factory='org.nanocontainer.script.xml.XMLContainerBuilderTestCase$TestFactory'>" +
    284                    "    <config-or-whatever/>" +
    285                    "  </component-instance>" +
    286                    "</container>");
    287
    288            PicoContainer pico = buildContainer(script);
    289            Object instance = pico.getComponentInstances().get(0);
    290            assertNotNull(instance);
    291            assertTrue(instance instanceof String);
    292            assertEquals("Hello", instance.toString());
    293        }
    294
    295        public void testComponentInstanceWithDefaultFactory() {
    296            Reader script = new StringReader("" +
    297                    "<container>" +
    298                    "  <component-instance>" +
    299                    "       <org.nanocontainer.script.xml.TestBean>" +
    300                    "               <foo>10</foo>" +
    301                    "               <bar>hello</bar>" +
    302                    "       </org.nanocontainer.script.xml.TestBean>" +
    303                    "  </component-instance>" +
    304                    "</container>");
    305
    306            PicoContainer pico = buildContainer(script);
    307            Object instance = pico.getComponentInstances().get(0);
    308            assertNotNull(instance);
    309            assertTrue(instance instanceof TestBean);
    310            assertEquals(10, ((TestBean) instance).getFoo());
    311            assertEquals("hello", ((TestBean) instance).getBar());
    312        }
    313
    314        public void testComponentInstanceWithBeanFactory() {
    315            Reader script = new StringReader("" +
    316                    "<container>" +
    317                    "  <component-instance factory='org.nanocontainer.script.xml.BeanComponentInstanceFactory'>" +
    318                    "       <org.nanocontainer.script.xml.TestBean>" +
    319                    "               <foo>10</foo>" +
    320                    "               <bar>hello</bar>" +
    321                    "       </org.nanocontainer.script.xml.TestBean>" +
    322                    "  </component-instance>" +
    323                    "</container>");
    324
    325            PicoContainer pico = buildContainer(script);
    326            Object instance = pico.getComponentInstances().get(0);
    327            assertNotNull(instance);
    328            assertTrue(instance instanceof TestBean);
    329            assertEquals(10, ((TestBean) instance).getFoo());
    330            assertEquals("hello", ((TestBean) instance).getBar());
    331        }
    332
    333        public void testComponentInstanceWithBeanFactoryAndInstanceThatIsDefinedInContainer() {
    334            Reader script = new StringReader("" +
    335                    "<container>" +
    336                    "  <component-instance key='date' factory='org.nanocontainer.script.xml.BeanComponentInstanceFactory'>" +
    337                    "    <java.util.Date>" +
    338                    "       <time>0</time>" +
    339                    "    </java.util.Date>" +
    340                    "  </component-instance>" +
    341                    "  <component-instance factory='org.nanocontainer.script.xml.BeanComponentInstanceFactory'>" +
    342                    "    <java.text.SimpleDateFormat>" +
    343                    "       <lenient>false</lenient>" +
    344                    "       <date name='2DigitYearStart'>date</date>" +
    345                    "    </java.text.SimpleDateFormat>" +
    346                    "  </component-instance>" +
    347                    "</container>");
    348
    349            PicoContainer pico = buildContainer(script);
    350            Object instance = pico.getComponentInstance(SimpleDateFormat.class);
    351            assertNotNull(instance);
    352            assertTrue(instance instanceof SimpleDateFormat);
    353            SimpleDateFormat format = ((SimpleDateFormat) instance);
    354            assertFalse(format.isLenient());
    355            assertEquals(new Date(0), format.get2DigitYearStart());
    356        }
    357
    358        public void testComponentInstanceWithKey() {
    359            Reader script = new StringReader("" +
    360                    "<container>" +
    361                    "  <component-instance key='aString'>" +
    362                    "    <string>Hello</string>" +
    363                    "  </component-instance>" +
    364                    "" +
    365                    "  <component-instance key='aLong'>" +
    366                    "    <long>22</long>" +
    367                    "  </component-instance>" +
    368                    "" +
    369                    "  <component-instance key='aButton'>" +
    370                    "    <javax.swing.JButton>" +
    371                    "      <text>Hello</text>" +
    372                    "      <alignmentX>0.88</alignmentX>" +
    373                    "    </javax.swing.JButton>" +
    374                    "  </component-instance>" +
    375                    "</container>");
    376
    377            PicoContainer pico = buildContainer(script);
    378            assertEquals("Hello", pico.getComponentInstance("aString"));
    379            assertEquals(new Long(22), pico.getComponentInstance("aLong"));
    380            JButton button = (JButton) pico.getComponentInstance("aButton");
    381            assertEquals("Hello", button.getText());
    382            assertEquals(0.88, button.getAlignmentX(), 0.01);
    383        }
    384
    385        public void testComponentInstanceWithClassKey() {
    386            Reader script = new StringReader("" +
    387                    "<container>" +
    388                    "  <component-instance class-name-key='java.util.Map' factory='org.nanocontainer.script.xml.XStreamComponentInstanceFactory'>" +
    389                    "    <properties>" +
    390                    "      <property name='foo' value='bar'/>" +
    391                    "    </properties>" +
    392                    "  </component-instance>" +
    393                    "</container>");
    394
    395            PicoContainer pico = buildContainer(script);
    396            Map map = (Map)pico.getComponentInstance(Map.class);
    397            assertNotNull(map);
    398            assertEquals("bar", map.get("foo"));
    399        }
    400
    401        public void testComponentInstanceWithFactoryAndKey() {
    402            Reader script = new StringReader("" +
    403                    "<container>" +
    404                    "  <component-instance factory='org.nanocontainer.script.xml.XMLContainerBuilderTestCase$TestFactory'" +
    405                    "                                               key='aKey'>" +
    406                    "    <config-or-whatever/>" +
    407                    "  </component-instance>" +
    408                    "</container>");
    409
    410            PicoContainer pico = buildContainer(script);
    411            Object instance = pico.getComponentInstance("aKey");
    412            assertNotNull(instance);
    413            assertTrue(instance instanceof String);
    414            assertEquals("Hello", instance.toString());
    415        }
    416
    417        public void testComponentInstanceWithContainerFactoryAndKey() {
    418            Reader script = new StringReader("" +
    419                    "<container component-instance-factory='org.nanocontainer.script.xml.XMLContainerBuilderTestCase$ContainerTestFactory'>" +
    420                    "  <component-instance factory='org.nanocontainer.script.xml.XMLContainerBuilderTestCase$TestFactory'" +
    421                    "                                               key='firstKey'>" +
    422                    "    <config-or-whatever/>" +
    423                    "  </component-instance>" +
    424                    "  <component-instance key='secondKey'>" +
    425                    "    <config-or-whatever/>" +
    426                    "  </component-instance>" +
    427                    "</container>");
    428
    429            PicoContainer pico = buildContainer(script);
    430            Object first = pico.getComponentInstance("firstKey");
    431            assertNotNull(first);
    432            assertTrue(first instanceof String);
    433            assertEquals("Hello", first.toString());
    434            Object second = pico.getComponentInstance("secondKey");
    435            assertNotNull(second);
    436            assertTrue(second instanceof String);
    437            assertEquals("ContainerHello", second.toString());
    438        }
    439
    440        public static class TestFactory implements XMLComponentInstanceFactory {
    441            public Object makeInstance(PicoContainer pico, Element elem, ClassLoader classLoader) {
    442                return "Hello";
    443            }
    444        }
    445
    446        public static class ContainerTestFactory implements XMLComponentInstanceFactory {
    447            public Object makeInstance(PicoContainer pico, Element elem, ClassLoader classLoader) {
    448                return "ContainerHello";
    449            }
    450        }
    451
    452        public void testInstantiationOfComponentsWithParams() {
    453            Reader script = new StringReader("" +
    454                    "<container>" +
    455                    "  <component-implementation class='org.nanocontainer.testmodel.WebServerConfigComp'>" +
    456                    "    <parameter><string>localhost</string></parameter>" +
    457                    "    <parameter><int>8080</int></parameter>" +
    458                    "  </component-implementation>" +
    459                    "  <component-implementation key='org.nanocontainer.testmodel.WebServer' class='org.nanocontainer.testmodel.WebServerImpl'/>" +
    460                    "</container>");
    461            PicoContainer pico = buildContainer(script);
    462            assertNotNull(pico.getComponentInstance(WebServerConfigComp.class));
    463            WebServerConfigComp config = (WebServerConfigComp) pico.getComponentInstanceOfType(WebServerConfigComp.class);
    464            assertEquals("localhost", config.getHost());
    465            assertEquals(8080, config.getPort());
    466        }
    467
    468        public void testInstantiationOfComponentsWithParameterInstancesOfSameComponent() {
    469            Reader script = new StringReader("" +
    470                    "<container>" +
    471                    "  <component-implementation class='org.nanocontainer.script.xml.TestBeanComposer'>" +
    472                    "               <parameter>" +
    473                    "                       <org.nanocontainer.script.xml.TestBean>" +
    474                    "                               <foo>10</foo>" +
    475                    "                               <bar>hello1</bar>" +
    476                    "                       </org.nanocontainer.script.xml.TestBean>" +
    477                    "               </parameter>" +
    478                    "               <parameter>" +
    479                    "                       <org.nanocontainer.script.xml.TestBean>" +
    480                    "                               <foo>10</foo>" +
    481                    "                               <bar>hello2</bar>" +
    482                    "                       </org.nanocontainer.script.xml.TestBean>" +
    483                    "               </parameter>" +
    484                    "  </component-implementation>" +
    485                    "</container>");
    486            PicoContainer pico = buildContainer(script);
    487            assertNotNull(pico.getComponentInstance(TestBeanComposer.class));
    488            TestBeanComposer composer = (TestBeanComposer) pico.getComponentInstance(TestBeanComposer.class);
    489            assertEquals("bean1", "hello1", composer.getBean1().getBar());
    490            assertEquals("bean2", "hello2", composer.getBean2().getBar());
    491        }
    492
    493        public void testInstantiationOfComponentsWithParameterInstancesOfSameComponentAndBeanFactory() {
    494            Reader script = new StringReader("" +
    495                    "<container>" +
    496                    "  <component-implementation class='org.nanocontainer.script.xml.TestBeanComposer'>" +
    497                    "               <parameter factory='org.nanocontainer.script.xml.BeanComponentInstanceFactory'>" +
    498                    "                       <org.nanocontainer.script.xml.TestBean>" +
    499                    "                               <foo>10</foo>" +
    500                    "                               <bar>hello1</bar>" +
    501                    "                       </org.nanocontainer.script.xml.TestBean>" +
    502                    "               </parameter>" +
    503                    "               <parameter factory='org.nanocontainer.script.xml.BeanComponentInstanceFactory'>" +
    504                    "                       <org.nanocontainer.script.xml.TestBean>" +
    505                    "                               <foo>10</foo>" +
    506                    "                               <bar>hello2</bar>" +
    507                    "                       </org.nanocontainer.script.xml.TestBean>" +
    508                    "               </parameter>" +
    509                    "  </component-implementation>" +
    510                    "</container>");
    511            PicoContainer pico = buildContainer(script);
    512            assertNotNull(pico.getComponentInstance(TestBeanComposer.class));
    513            TestBeanComposer composer = (TestBeanComposer) pico.getComponentInstance(TestBeanComposer.class);
    514            assertEquals("bean1", "hello1", composer.getBean1().getBar());
    515            assertEquals("bean2", "hello2", composer.getBean2().getBar());
    516        }
    517
    518        public void testInstantiationOfComponentsWithParameterKeys() {
    519            Reader script = new StringReader("" +
    520                    "<container>" +
    521                    "  <component-instance key='bean1'>" +
    522                    "       <org.nanocontainer.script.xml.TestBean>" +
    523                    "               <foo>10</foo>" +
    524                    "               <bar>hello1</bar>" +
    525                    "       </org.nanocontainer.script.xml.TestBean>" +
    526                    "  </component-instance>" +
    527                    "  <component-instance key='bean2'>" +
    528                    "       <org.nanocontainer.script.xml.TestBean>" +
    529                    "               <foo>10</foo>" +
    530                    "               <bar>hello2</bar>" +
    531                    "       </org.nanocontainer.script.xml.TestBean>" +
    532                    "  </component-instance>" +
    533                    "  <component-implementation class='org.nanocontainer.script.xml.TestBeanComposer'>" +
    534                    "               <parameter key='bean1'/>" +
    535                    "               <parameter key='bean2'/>" +
    536                    "  </component-implementation>" +
    537                    "</container>");
    538            PicoContainer pico = buildContainer(script);
    539            assertNotNull(pico.getComponentInstance(TestBeanComposer.class));
    540            TestBeanComposer composer = (TestBeanComposer) pico.getComponentInstance(TestBeanComposer.class);
    541            assertEquals("bean1", "hello1", composer.getBean1().getBar());
    542            assertEquals("bean2", "hello2", composer.getBean2().getBar());
    543        }
    544
    545        public void testInstantiationOfComponentsWithComponentAdapter() {
    546            Reader script = new StringReader("" +
    547                    "<container>" +
    548                    "  <component-instance key='bean1'>" +
    549                    "       <org.nanocontainer.script.xml.TestBean>" +
    550                    "               <foo>10</foo>" +
    551                    "               <bar>hello1</bar>" +
    552                    "       </org.nanocontainer.script.xml.TestBean>" +
    553                    "  </component-instance>" +
    554                    "  <component-instance key='bean2'>" +
    555                    "       <org.nanocontainer.script.xml.TestBean>" +
    556                    "               <foo>10</foo>" +
    557                    "               <bar>hello2</bar>" +
    558                    "       </org.nanocontainer.script.xml.TestBean>" +
    559                    "  </component-instance>" +
    560                    "  <component-adapter key='beanKey' class='org.nanocontainer.script.xml.TestBeanComposer'>" +
    561                    "               <parameter key='bean1'/>" +
    562                    "               <parameter key='bean2'/>" +
    563                    "  </component-adapter>" +
    564                    "</container>");
    565            PicoContainer pico = buildContainer(script);
    566            assertNotNull(pico.getComponentInstance("beanKey"));
    567            TestBeanComposer composer = (TestBeanComposer) pico.getComponentInstance("beanKey");
    568            assertEquals("bean1", "hello1", composer.getBean1().getBar());
    569            assertEquals("bean2", "hello2", composer.getBean2().getBar());
    570        }
    571
    572        public void testComponentAdapterWithSpecifiedFactory() {
    573            Reader script = new StringReader("" +
    574                    "<container>" +
    575                    "  <component-instance key='bean1'>" +
    576                    "       <org.nanocontainer.script.xml.TestBean>" +
    577                    "               <foo>10</foo>" +
    578                    "               <bar>hello1</bar>" +
    579                    "       </org.nanocontainer.script.xml.TestBean>" +
    580                    "  </component-instance>" +
    581                    "  <component-instance key='bean2'>" +
    582                    "       <org.nanocontainer.script.xml.TestBean>" +
    583                    "               <foo>10</foo>" +
    584                    "               <bar>hello2</bar>" +
    585                    "       </org.nanocontainer.script.xml.TestBean>" +
    586                    "  </component-instance>" +
    587                    "  <component-adapter key='beanKey' class='org.nanocontainer.script.xml.TestBeanComposer'" +
    588                    "                                       factory='" + DefaultComponentAdapterFactory.class.getName() + "'>" +
    589                    "               <parameter key='bean1'/>" +
    590                    "               <parameter key='bean2'/>" +
    591                    "  </component-adapter>" +
    592                    "</container>");
    593            PicoContainer pico = buildContainer(script);
    594            assertNotNull(pico.getComponentInstance("beanKey"));
    595            TestBeanComposer composer = (TestBeanComposer) pico.getComponentInstance("beanKey");
    596            assertEquals("bean1", "hello1", composer.getBean1().getBar());
    597            assertEquals("bean2", "hello2", composer.getBean2().getBar());
    598        }
    599
    600        public void testComponentAdapterWithNoKeyUsesTypeAsKey() {
    601            Reader script = new StringReader("" +
    602                    "<container>" +
    603                    "  <component-adapter class='org.nanocontainer.script.xml.TestBeanComposer'/>" +
    604                    "</container>");
    605            PicoContainer pico = buildContainer(script);
    606            ComponentAdapter adapter = (ComponentAdapter)pico.getComponentAdapters().iterator().next();
    607            assertSame(TestBeanComposer.class, adapter.getComponentImplementation());
    608        }
    609
    610        public void testComponentAdapterWithNoClassThrowsNanoContainerMarkupException() {
    611            Reader script = new StringReader("" +
    612                    "<container>" +
    613                    "  <component-adapter key='beanKey'/> " +
    614                    "</container>");
    615            try {
    616                buildContainer(script);
    617                fail();
    618            } catch (NanoContainerMarkupException expected) {
    619                assertEquals("'class' attribute not specified for component-adapter", expected.getMessage());
    620            }
    621        }
    622
    623        // This is of little value given that nested adapters can't be specified in XML.
    624        public void testComponentAdapterClassCanBeSpecifiedInContainerElement() {
    625            Reader script = new StringReader("" +
    626                    "<container component-adapter-factory='" + ConstructorInjectionComponentAdapterFactory.class.getName() + "'>" +
    627                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    628                    "</container>");
    629
    630            PicoContainer pico = buildContainer(script);
    631            Object wsc1 = pico.getComponentInstanceOfType(WebServerConfig.class);
    632            Object wsc2 = pico.getComponentInstanceOfType(WebServerConfig.class);
    633
    634            assertNotSame(wsc1, wsc2);
    635        }
    636
    637        public void testComponentMonitorCanBeSpecified() {
    638            Reader script = new StringReader("" +
    639                    "<container component-monitor='" + StaticWriterComponentMonitor.class.getName() + "'>" +
    640                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    641                    "</container>");
    642
    643            PicoContainer pico = buildContainer(script);
    644            pico.getComponentInstanceOfType(WebServerConfig.class);
    645            assertTrue(StaticWriterComponentMonitor.WRITER.toString().length() > 0);
    646        }
    647
    648        public void testComponentMonitorCanBeSpecifiedIfCAFIsSpecified() {
    649            Reader script = new StringReader("" +
    650                    "<container component-adapter-factory='" +DefaultComponentAdapterFactory.class.getName() +
    651                    "' component-monitor='" + StaticWriterComponentMonitor.class.getName() + "'>" +
    652                    "  <component-implementation class='org.nanocontainer.testmodel.DefaultWebServerConfig'/>" +
    653                    "</container>");
    654
    655            PicoContainer pico = buildContainer(script);
    656            pico.getComponentInstanceOfType(WebServerConfig.class);
    657            assertTrue(StaticWriterComponentMonitor.WRITER.toString().length() > 0);
    658        }
    659
    660        public void testComponentCanUsePredefinedCAF() {
    661            Reader script = new StringReader("" +
    662                    "<container>" +
    663                    "  <component-adapter-factory class='org.picocontainer.defaults.ConstructorInjectionComponentAdapterFactory' key='factory'/>" +
    664                    "  <component-adapter class='org.nanocontainer.testmodel.DefaultWebServerConfig' factory='factory'/>" +
    665                    "</container>");
    666            PicoContainer pico = buildContainer(script);
    667            WebServerConfig cfg1 = (WebServerConfig)pico.getComponentInstanceOfType(WebServerConfig.class);
    668            WebServerConfig cfg2 = (WebServerConfig)pico.getComponentInstanceOfType(WebServerConfig.class);
    669            assertNotSame("Instances for components registered with a CICA must not be the same", cfg1, cfg2);
    670        }
    671
    672        public void testComponentCanUsePredefinedNestedCAF() {
    673            Reader script = new StringReader("" +
    674                    "<container>" +
    675                    "  <component-adapter-factory class='org.picocontainer.defaults.ImplementationHidingComponentAdapterFactory' key='factory'>" +
    676                    "    <component-adapter-factory class='org.picocontainer.defaults.ConstructorInjectionComponentAdapterFactory'/>" +
    677                    "  </component-adapter-factory>" +
    678                    "  <component-adapter class-name-key='org.nanocontainer.testmodel.WebServerConfig' class='org.nanocontainer.testmodel.DefaultWebServerConfig' factory='factory'/>" +
    679                    "</container>");
    680            PicoContainer pico = buildContainer(script);
    681            WebServerConfig cfg1 = (WebServerConfig)pico.getComponentInstanceOfType(WebServerConfig.class);
    682            WebServerConfig cfg2 = (WebServerConfig)pico.getComponentInstanceOfType(WebServerConfig.class);
    683            assertNotSame("Instances for components registered with a CICA must not be the same", cfg1, cfg2);
    684            assertFalse("Instance exposes only interface", cfg1 instanceof DefaultWebServerConfig);
    685        }
    686
    687        public void testComponentCanUsePredefinedCAFWithParameters() {
    688            Reader script = new StringReader("" +
    689                    "<container>" +
    690                    "  <component-adapter-factory class='org.picocontainer.defaults.ConstructorInjectionComponentAdapterFactory' key='factory'>" +
    691                    "    <parameter><boolean>true</boolean></parameter>" +
    692                    "  </component-adapter-factory>" +
    693                    "  <component-adapter key='pc1' class='org.nanocontainer.script.xml.XMLContainerBuilderTestCase$PrivateComponent' factory='org.picocontainer.defaults.ConstructorInjectionComponentAdapterFactory'/>" +
    694                    "  <component-adapter key='pc2' class='org.nanocontainer.script.xml.XMLContainerBuilderTestCase$PrivateComponent' factory='factory'/>" +
    695                    "</container>");
    696            PicoContainer pico = buildContainer(script);
    697            PrivateComponent pc2 = (PrivateComponent)pico.getComponentInstance("pc2");
    698            assertNotNull(pc2);
    699            try {
    700                pico.getComponentInstance("pc1");
    701                fail("Thrown " + PicoException.class.getName() + " expected");
    702            } catch (final PicoException e) {
    703                assertTrue(e.getMessage().indexOf(PrivateComponent.class.getName())>0);
    704            }
    705        }
    706
    707        public void testChainOfDecoratingPicoContainersCanDoInterceptionOfMutablePicoContainerMethods() throws ClassNotFoundException {
    708
    709           Reader script = new StringReader("" +
    710                    "<container>\n" +
    711                   "   <decorating-picocontainer class='"+FooDecoratingPicoContainer.class.getName()+"'/>" +
    712                   "   <decorating-picocontainer class='"+BarDecoratingPicoContainer.class.getName()+"'/>" +
    713                    "  <component-implementation class='java.util.Vector'/>" +
    714                    "</container>");
    715
    716            PicoContainer pico = buildContainer(script);
    717
    718            // decorators are fairly dirty - they replace a very select implementation in this TestCase.
    719            assertNotNull(pico.getComponentInstanceOfType(ArrayList.class));
    720            assertNull(pico.getComponentInstanceOfType(Vector.class));
    721        }
    722
    723        public void testChainOfWrappedComponents() {
    724
    725           Reader script = new StringReader("" +
    726                    "<container>\n" +
    727                   "   <component-implementation key='wrapped' class='"+SimpleTouchable.class.getName()+"'/>" +
    728                   "   <component-implementation class-name-key=\'"+Touchable.class.getName()+"\' class='"+WrapsTouchable.class.getName()+"'/>" +
    729                    "</container>");
    730
    731            PicoContainer pico = buildContainer(script);
    732
    733            // decorators are fairly dirty - they replace a very select implementation in this TestCase.
    734            assertNotNull(pico.getComponentInstanceOfType(Touchable.class));
    735        }
    736
    737        private PicoContainer buildContainer(Reader script) {
    738            return buildContainer(new XMLContainerBuilder(script, getClass().getClassLoader()), null, "SOME_SCOPE");
    739        }
    740
    741        static public class StaticWriterComponentMonitor extends WriterComponentMonitor {
    742            static Writer WRITER = new StringWriter();
    743
    744            public StaticWriterComponentMonitor() {
    745                super(WRITER);
    746            }
    747
    748        }
    749
    750        static private class PrivateComponent {
    751        }
    752
    753        // TODO: Move this into pico-tck as soon as nano is dependend on a pico snapshot again ...
    754        public static class WrapsTouchable implements Touchable {
    755            private final Touchable wrapped;
    756
    757            public WrapsTouchable(final Touchable wrapped) {
    758                this.wrapped = wrapped;
    759            }
    760
    761            public void touch() {
    762                this.wrapped.touch();
    763            }
    764        }
    765    }
    766