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