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