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ø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