001    /*******************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved. 
003     * ---------------------------------------------------------------------------
004     * The software in this package is published under the terms of the BSD style
005     * license a copy of which has been included with this distribution in the
006     * LICENSE.txt file.
007     ******************************************************************************/
008    package org.picocontainer.script.xml;
009    
010    import java.io.File;
011    import java.io.IOException;
012    import java.io.Reader;
013    import java.io.Serializable;
014    import java.net.MalformedURLException;
015    import java.net.URL;
016    import java.security.Permission;
017    import java.util.ArrayList;
018    import java.util.List;
019    import java.util.Properties;
020    
021    import javax.xml.parsers.DocumentBuilder;
022    import javax.xml.parsers.DocumentBuilderFactory;
023    import javax.xml.parsers.ParserConfigurationException;
024    
025    import org.picocontainer.Characteristics;
026    import org.picocontainer.ComponentFactory;
027    import org.picocontainer.DefaultPicoContainer;
028    import org.picocontainer.MutablePicoContainer;
029    import org.picocontainer.Parameter;
030    import org.picocontainer.PicoClassNotFoundException;
031    import org.picocontainer.PicoCompositionException;
032    import org.picocontainer.PicoContainer;
033    import org.picocontainer.classname.ClassPathElement;
034    import org.picocontainer.classname.ClassLoadingPicoContainer;
035    import org.picocontainer.classname.DefaultClassLoadingPicoContainer;
036    import org.picocontainer.behaviors.Caching;
037    import org.picocontainer.injectors.ConstructorInjection;
038    import org.picocontainer.lifecycle.NullLifecycleStrategy;
039    import org.picocontainer.monitors.NullComponentMonitor;
040    import org.picocontainer.parameters.ComponentParameter;
041    import org.picocontainer.parameters.ConstantParameter;
042    import org.picocontainer.classname.ClassName;
043    import org.picocontainer.script.LifecycleMode;
044    import org.picocontainer.script.ScriptedBuilder;
045    import org.picocontainer.script.ScriptedContainerBuilder;
046    import org.picocontainer.script.ScriptedPicoContainerMarkupException;
047    import org.w3c.dom.Element;
048    import org.w3c.dom.NodeList;
049    import org.xml.sax.EntityResolver;
050    import org.xml.sax.InputSource;
051    import org.xml.sax.SAXException;
052    
053    /**
054     * This class builds up a hierarchy of PicoContainers from an XML configuration file.
055     *
056     * @author Paul Hammant
057     * @author Aslak Hellesøy
058     * @author Jeppe Cramon
059     * @author Mauro Talevi
060     */
061    public class XMLContainerBuilder extends ScriptedContainerBuilder {
062    
063        private final static String DEFAULT_COMPONENT_INSTANCE_FACTORY = BeanComponentInstanceFactory.class.getName();
064    
065        private final static String CONTAINER = "container";
066        private final static String CLASSPATH = "classpath";
067        private final static String CLASSLOADER = "classloader";
068        private static final String CLASS_NAME_KEY = "class-name-key";
069        private final static String COMPONENT = "component";
070        private final static String COMPONENT_IMPLEMENTATION = "component-implementation";
071        private final static String COMPONENT_INSTANCE = "component-instance";
072        private final static String COMPONENT_ADAPTER = "component-adapter";
073        private final static String COMPONENT_ADAPTER_FACTORY = "component-adapter-factory";
074        private final static String COMPONENT_INSTANCE_FACTORY = "component-instance-factory";
075        private final static String COMPONENT_MONITOR = "component-monitor";
076        private final static String CLASS = "class";
077        private final static String FACTORY = "factory";
078        private final static String FILE = "file";
079        private final static String KEY = "key";
080        private final static String EMPTY_COLLECTION = "empty-collection";
081        private final static String COMPONENT_VALUE_TYPE = "component-value-type";
082        private final static String COMPONENT_KEY_TYPE = "component-key-type";
083        private final static String PARAMETER = "parameter";
084        private final static String URL = "url";
085    
086        private final static String CLASSNAME = "classname";
087        private final static String CONTEXT = "context";
088        private final static String VALUE = "value";
089    
090        private static final String EMPTY = "";
091    
092        private Element rootElement;
093        /**
094         * The XMLComponentInstanceFactory globally defined for the container.
095         * It may be overridden at node level.
096         */
097        private XMLComponentInstanceFactory componentInstanceFactory;
098    
099        public XMLContainerBuilder(Reader script, ClassLoader classLoader) {
100            this(script,classLoader, LifecycleMode.AUTO_LIFECYCLE);
101        }
102        
103        public XMLContainerBuilder(Reader script, ClassLoader classLoader, LifecycleMode lifecycleMode) {
104            super(script, classLoader, lifecycleMode);
105            try {
106                DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
107                parse(documentBuilder, new InputSource(script));
108            } catch (ParserConfigurationException e) {
109                throw new ScriptedPicoContainerMarkupException(e);
110            }
111        }
112    
113        public XMLContainerBuilder(final URL script, ClassLoader classLoader) {
114            this(script,classLoader, LifecycleMode.AUTO_LIFECYCLE);
115        }
116        
117        public XMLContainerBuilder(final URL script, ClassLoader classLoader, LifecycleMode lifecycleMode) {
118            super(script, classLoader, lifecycleMode);
119            try {
120                DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
121                documentBuilder.setEntityResolver(new EntityResolver() {
122                    public InputSource resolveEntity(String publicId, String systemId) throws IOException {
123                        URL url = new URL(script, systemId);
124                        return new InputSource(url.openStream());
125                    }
126                });
127                parse(documentBuilder, new InputSource(script.toString()));
128            } catch (ParserConfigurationException e) {
129                throw new ScriptedPicoContainerMarkupException(e);
130            }
131        }
132    
133        private void parse(DocumentBuilder documentBuilder, InputSource inputSource) {
134            try {
135                rootElement = documentBuilder.parse(inputSource).getDocumentElement();
136            } catch (SAXException e) {
137                throw new ScriptedPicoContainerMarkupException(e);
138            } catch (IOException e) {
139                throw new ScriptedPicoContainerMarkupException(e);
140            }
141        }
142    
143        protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object assemblyScope) {
144            try {
145                // create ComponentInstanceFactory for the container
146                boolean caching = boolValue(rootElement.getAttribute("caching"), true);
147                componentInstanceFactory = createComponentInstanceFactory(rootElement.getAttribute(COMPONENT_INSTANCE_FACTORY));
148                MutablePicoContainer childContainer = createMutablePicoContainer(rootElement.getAttribute(COMPONENT_ADAPTER_FACTORY),
149                        rootElement.getAttribute(COMPONENT_MONITOR), parentContainer, caching);
150                populateContainer(childContainer);
151                return childContainer;
152            } catch (PicoClassNotFoundException e) {
153                throw new ScriptedPicoContainerMarkupException("Class not found:" + e.getMessage(), e);
154            }
155        }
156    
157        private MutablePicoContainer createMutablePicoContainer(String componentFactoryName, String monitorName, PicoContainer parentContainer, boolean caching) throws PicoCompositionException {
158    
159            ScriptedBuilder builder = new ScriptedBuilder(parentContainer);
160            if (caching) builder.withCaching();
161            return builder
162                .withClassLoader(getClassLoader())
163                .withLifecycle()
164                .withComponentFactory(componentFactoryName)
165                .withMonitor(monitorName)
166                .buildPico();
167    
168        }
169    
170        public void populateContainer(MutablePicoContainer container) {
171            try {
172                String parentClass = rootElement.getAttribute("parentclassloader");
173                ClassLoader classLoader = getClassLoader();
174                if (parentClass != null && !EMPTY.equals(parentClass)) {
175                    classLoader = classLoader.loadClass(parentClass).getClassLoader();
176                }
177                ClassLoadingPicoContainer scriptedContainer = new DefaultClassLoadingPicoContainer(classLoader, container);
178                registerComponentsAndChildContainers(scriptedContainer, rootElement, new DefaultClassLoadingPicoContainer(getClassLoader()));
179            } catch (ClassNotFoundException e) {
180                throw new ScriptedPicoContainerMarkupException("Class not found: " + e.getMessage(), e);
181            } catch (IOException e) {
182                throw new ScriptedPicoContainerMarkupException(e);
183            } catch (SAXException e) {
184                throw new ScriptedPicoContainerMarkupException(e);
185            }
186        }
187    
188        private void registerComponentsAndChildContainers(ClassLoadingPicoContainer parentContainer, Element containerElement, ClassLoadingPicoContainer knownComponentAdapterFactories) throws ClassNotFoundException, IOException, SAXException {
189    
190            ClassLoadingPicoContainer metaContainer = new DefaultClassLoadingPicoContainer(getClassLoader(), knownComponentAdapterFactories);
191            NodeList children = containerElement.getChildNodes();
192            // register classpath first, regardless of order in the document.
193            for (int i = 0; i < children.getLength(); i++) {
194                if (children.item(i) instanceof Element) {
195                    Element childElement = (Element) children.item(i);
196                    String name = childElement.getNodeName();
197                    if (CLASSPATH.equals(name)) {
198                        registerClasspath(parentContainer, childElement);
199                    }
200                }
201            }
202            for (int i = 0; i < children.getLength(); i++) {
203                if (children.item(i) instanceof Element) {
204                    Element childElement = (Element) children.item(i);
205                    String name = childElement.getNodeName();
206                    if (CONTAINER.equals(name)) {
207                        MutablePicoContainer childContainer = parentContainer.makeChildContainer();
208                        ClassLoadingPicoContainer childPicoContainer = new DefaultClassLoadingPicoContainer(parentContainer.getComponentClassLoader(), childContainer);
209                        registerComponentsAndChildContainers(childPicoContainer, childElement, metaContainer);
210                    } else if (COMPONENT_IMPLEMENTATION.equals(name)
211                            || COMPONENT.equals(name)) {
212                        registerComponent(parentContainer, childElement);
213                    } else if (COMPONENT_INSTANCE.equals(name)) {
214                        registerComponentInstance(parentContainer, childElement);
215                    } else if (COMPONENT_ADAPTER.equals(name)) {
216                        registerComponentAdapter(parentContainer, childElement, metaContainer);
217                    } else if (COMPONENT_ADAPTER_FACTORY.equals(name)) {
218                        addComponentFactory(childElement, metaContainer);
219                    } else if (CLASSLOADER.equals(name)) {
220                        registerClassLoader(parentContainer, childElement, metaContainer);
221                    } else if (!CLASSPATH.equals(name)) {
222                        throw new ScriptedPicoContainerMarkupException("Unsupported element:" + name);
223                    }
224                }
225            }
226        }
227    
228    
229        private void addComponentFactory(Element element, ClassLoadingPicoContainer metaContainer) throws MalformedURLException, ClassNotFoundException {
230            if (notSet(element.getAttribute(KEY))) {
231                throw new ScriptedPicoContainerMarkupException("'" + KEY + "' attribute not specified for " + element.getNodeName());
232            }
233            Element node = (Element)element.cloneNode(false);
234            NodeList children = element.getChildNodes();
235            for (int i = 0; i < children.getLength(); i++) {
236                if (children.item(i) instanceof Element) {
237                    Element childElement = (Element) children.item(i);
238                    String name = childElement.getNodeName();
239                    if (COMPONENT_ADAPTER_FACTORY.equals(name)) {
240                        if (!"".equals(childElement.getAttribute(KEY))) {
241                            throw new ScriptedPicoContainerMarkupException("'" + KEY + "' attribute must not be specified for nested " + element.getNodeName());
242                        }
243                        childElement = (Element)childElement.cloneNode(true);
244                        String key = String.valueOf(System.identityHashCode(childElement));
245                        childElement.setAttribute(KEY, key);
246                        addComponentFactory(childElement, metaContainer);
247                        // replace nested CAF with a ComponentParameter using an internally generated key
248                        Element parameter = node.getOwnerDocument().createElement(PARAMETER);
249                        parameter.setAttribute(KEY, key);
250                        node.appendChild(parameter);
251                    } else if (PARAMETER.equals(name)) {
252                        node.appendChild(childElement.cloneNode(true));
253                    }
254                }
255            }
256            // handle CAF now as standard component in the metaContainer
257            registerComponent(metaContainer, node);
258        }
259    
260        private void registerClassLoader(ClassLoadingPicoContainer parentContainer, Element childElement, ClassLoadingPicoContainer metaContainer) throws IOException, SAXException, ClassNotFoundException {
261            String parentClass = childElement.getAttribute("parentclassloader");
262            ClassLoader parentClassLoader = parentContainer.getComponentClassLoader();
263            if (parentClass != null && !EMPTY.equals(parentClass)) {
264                parentClassLoader = parentClassLoader.loadClass(parentClass).getClassLoader();
265            }
266            ClassLoadingPicoContainer scripted = new DefaultClassLoadingPicoContainer(parentClassLoader, parentContainer);
267            registerComponentsAndChildContainers(scripted, childElement, metaContainer);
268        }
269    
270        private void registerClasspath(ClassLoadingPicoContainer container, Element classpathElement) throws IOException, ClassNotFoundException {
271            NodeList children = classpathElement.getChildNodes();
272            for (int i = 0; i < children.getLength(); i++) {
273                if (children.item(i) instanceof Element) {
274                    Element childElement = (Element) children.item(i);
275    
276                    String fileName = childElement.getAttribute(FILE);
277                    String urlSpec = childElement.getAttribute(URL);
278                    URL url;
279                    if (urlSpec != null && !EMPTY.equals(urlSpec)) {
280                        url = new URL(urlSpec);
281                    } else {
282                        File file = new File(fileName);
283                        if (!file.exists()) {
284                            throw new IOException(file.getAbsolutePath() + " doesn't exist");
285                        }
286                        url = file.toURL();
287                    }
288                    ClassPathElement cpe = container.addClassLoaderURL(url);
289                    registerPermissions(cpe, childElement);
290                }
291            }
292        }
293    
294        private void registerPermissions(ClassPathElement classPathElement, Element classPathXmlElement) throws ClassNotFoundException {
295            NodeList children = classPathXmlElement.getChildNodes();
296            for (int i = 0; i < children.getLength(); i++) {
297                if (children.item(i) instanceof Element) {
298                    Element childElement = (Element) children.item(i);
299    
300                    String permissionClassName = childElement.getAttribute(CLASSNAME);
301                    String action = childElement.getAttribute(CONTEXT);
302                    String value = childElement.getAttribute(VALUE);
303                    MutablePicoContainer mpc = new DefaultPicoContainer();
304                    mpc.addComponent(Permission.class, Class.forName(permissionClassName), new ConstantParameter(action), new ConstantParameter(value));
305    
306                    Permission permission = mpc.getComponent(Permission.class);
307                    classPathElement.grantPermission(permission);
308                }
309            }
310    
311        }
312    
313        private void registerComponent(ClassLoadingPicoContainer container, Element element) throws ClassNotFoundException, MalformedURLException {
314            String className = element.getAttribute(CLASS);
315            if (notSet(className)) {
316                throw new ScriptedPicoContainerMarkupException("'" + CLASS + "' attribute not specified for " + element.getNodeName());
317            }
318    
319            Parameter[] parameters = createChildParameters(container, element);
320            Class<?> clazz = container.getComponentClassLoader().loadClass(className);
321            Object key = element.getAttribute(KEY);
322            String classKey = element.getAttribute(CLASS_NAME_KEY);
323            if (notSet(key)) {
324                if (!notSet(classKey)) {
325                    key = getClassLoader().loadClass(classKey);
326                } else {
327                    key = clazz;
328                }
329            }
330            if (parameters == null) {
331                container.addComponent(key, clazz);
332            } else {
333                container.addComponent(key, clazz, parameters);
334            }
335        }
336    
337    
338    
339        private Parameter[] createChildParameters(ClassLoadingPicoContainer container, Element element) throws ClassNotFoundException, MalformedURLException {
340            List<Parameter> parametersList = new ArrayList<Parameter>();
341            NodeList children = element.getChildNodes();
342            for (int i = 0; i < children.getLength(); i++) {
343                if (children.item(i) instanceof Element) {
344                    Element childElement = (Element) children.item(i);
345                    if (PARAMETER.equals(childElement.getNodeName())) {
346                        parametersList.add(createParameter(container, childElement));
347                    }
348                }
349            }
350    
351            Parameter[] parameters = null;
352            if (!parametersList.isEmpty()) {
353                parameters = parametersList.toArray(new Parameter[parametersList.size()]);
354            }
355            return parameters;
356        }
357    
358        /**
359         * Build the org.picocontainer.Parameter from the <code>parameter</code> element. This could
360         * create either a ComponentParameter or ConstantParameter instance,
361         * depending on the values of the element's attributes. This is somewhat
362         * complex because there are five constructors for ComponentParameter and one for 
363         * ConstantParameter. These are:
364         * 
365         * <a href="http://www.picocontainer.org/picocontainer/latest/picocontainer/apidocs/org/picocontainer/defaults/ComponentParameter.html">ComponentParameter Javadocs</a>:
366         * 
367         * <code>ComponentParameter() - Expect any scalar paramter of the appropriate type or an Array.
368         *       ComponentParameter(boolean emptyCollection) - Expect any scalar paramter of the appropriate type or an Array.
369         *       ComponentParameter(Class componentValueType, boolean emptyCollection) - Expect any scalar paramter of the appropriate type or the collecting type Array,Collectionor Map.
370         *       ComponentParameter(Class componentKeyType, Class componentValueType, boolean emptyCollection) - Expect any scalar paramter of the appropriate type or the collecting type Array,Collectionor Map.
371         *       ComponentParameter(Object componentKey) - Expect a parameter matching a component of a specific key.</code>
372         * 
373         * and
374         * 
375         * <a href="http://www.picocontainer.org/picocontainer/latest/picocontainer/apidocs/org/picocontainer/defaults/ConstantParameter.html">ConstantParameter Javadocs</a>:
376         * 
377         * <code>ConstantParameter(Object value)</code>
378         * 
379         * The rules for this are, in order:
380         * 
381         * 1) If the <code>key</code> attribute is not null/empty, the fifth constructor will be used.
382         * 2) If the <code>componentKeyType</code> attribute is not null/empty, the fourth constructor will be used.  
383         *    In this case, both the <code>componentValueType</code> and <code>emptyCollection</code> attributes must be non-null/empty or an exception will be thrown.
384         * 3) If the <code>componentValueType</code> attribute is not null/empty, the third constructor will be used.
385         *    In this case, the <code>emptyCollection</code> attribute must be non-null/empty.
386         * 4) If the <code>emptyCollection</code> attribute is not null/empty, the second constructor will be used.
387         * 5) If there is no child element of the parameter, the first constructor will be used.
388         * 6) Otherwise, the return value will be a ConstantParameter with the return from the createInstance value.
389         * @param element
390         * @param pico
391         * @return
392         * @throws ClassNotFoundException
393         * @throws MalformedURLException
394         */
395        private Parameter createParameter(PicoContainer pico, Element element) throws ClassNotFoundException, MalformedURLException {
396            final Parameter parameter;
397            String key = element.getAttribute(KEY);
398            String emptyCollectionString = element.getAttribute(EMPTY_COLLECTION);
399            String componentValueTypeString = element.getAttribute(COMPONENT_VALUE_TYPE);
400            String componentKeyTypeString = element.getAttribute(COMPONENT_KEY_TYPE);
401    
402            // key not null/empty takes precidence 
403            if (key != null && !EMPTY.equals(key)) {
404                parameter = new ComponentParameter(key);
405            } else if (componentKeyTypeString != null && !EMPTY.equals(componentKeyTypeString)) {
406                if (emptyCollectionString == null || componentValueTypeString == null || 
407                        EMPTY.equals(emptyCollectionString) || EMPTY.equals(componentValueTypeString)) {
408                    
409                    throw new ScriptedPicoContainerMarkupException("The componentKeyType attribute was specified (" +
410                            componentKeyTypeString + ") but one or both of the emptyCollection (" + 
411                            emptyCollectionString + ") or componentValueType (" + componentValueTypeString + 
412                            ") was empty or null.");
413                }
414                
415                Class<?> componentKeyType = getClassLoader().loadClass(componentKeyTypeString);
416                Class<?> componentValueType = getClassLoader().loadClass(componentValueTypeString);
417                
418                boolean emptyCollection = Boolean.valueOf(emptyCollectionString);
419                
420                parameter = new ComponentParameter(componentKeyType, componentValueType, emptyCollection);
421            } else if (componentValueTypeString != null && !EMPTY.equals(componentValueTypeString)) {
422                if (emptyCollectionString == null || EMPTY.equals(emptyCollectionString)) {
423                    
424                    throw new ScriptedPicoContainerMarkupException("The componentValueType attribute was specified (" +
425                            componentValueTypeString + ") but the emptyCollection (" + 
426                            emptyCollectionString + ") was empty or null.");
427                }
428                
429                Class<?> componentValueType = getClassLoader().loadClass(componentValueTypeString);
430                
431                boolean emptyCollection = Boolean.valueOf(emptyCollectionString);
432                
433                parameter = new ComponentParameter(componentValueType, emptyCollection);
434            } else if (emptyCollectionString != null && !EMPTY.equals(emptyCollectionString)) {
435                boolean emptyCollection = Boolean.valueOf(emptyCollectionString);
436                
437                parameter = new ComponentParameter(emptyCollection);
438            }
439            else if (getFirstChildElement(element, false) == null) {
440                parameter = new ComponentParameter();
441            } else {
442                Object instance = createInstance(pico, element);
443                parameter = new ConstantParameter(instance);
444            }
445            return parameter;
446        }
447    
448    
449        private void registerComponentInstance(ClassLoadingPicoContainer container, Element element) throws ClassNotFoundException, PicoCompositionException, MalformedURLException {
450            Object instance = createInstance(container, element);
451            String key = element.getAttribute(KEY);
452            String classKey = element.getAttribute(CLASS_NAME_KEY);
453            if (notSet(key)) {
454                if (!notSet(classKey)) {
455                    container.addComponent(getClassLoader().loadClass(classKey), instance);
456                } else {
457                    container.addComponent(instance);
458                }
459            } else {
460                container.addComponent(key, instance);
461            }
462        }
463    
464        private Object createInstance(PicoContainer pico, Element element) throws MalformedURLException {
465            XMLComponentInstanceFactory factory = createComponentInstanceFactory(element.getAttribute(FACTORY));
466            Element instanceElement = getFirstChildElement(element, true);
467            return factory.makeInstance(pico, instanceElement, getClassLoader());
468        }
469    
470        private Element getFirstChildElement(Element parent, boolean fail) {
471            NodeList children = parent.getChildNodes();
472            Element child = null;
473            for (int i = 0; i < children.getLength(); i++) {
474                if (children.item(i) instanceof Element) {
475                    child = (Element) children.item(i);
476                    break;
477                }
478            }
479            if (child == null && fail) {
480                throw new ScriptedPicoContainerMarkupException(parent.getNodeName() + " needs a child element");
481            }
482            return child;
483        }
484    
485        private XMLComponentInstanceFactory createComponentInstanceFactory(String factoryClass) {
486            if ( notSet(factoryClass)) {
487                // no factory has been specified for the node
488                // return globally defined factory for the container - if there is one
489                if (componentInstanceFactory != null) {
490                    return componentInstanceFactory;
491                }
492                factoryClass = DEFAULT_COMPONENT_INSTANCE_FACTORY;
493            }
494    
495            // using a PicoContainer is overkill here.
496            try {
497                return (XMLComponentInstanceFactory)getClassLoader().loadClass(factoryClass).newInstance();
498            } catch (InstantiationException e) {
499                throw new PicoCompositionException(e);
500            } catch (IllegalAccessException e) {
501                throw new PicoCompositionException(e);
502            } catch (ClassNotFoundException e) {
503                throw new PicoClassNotFoundException(factoryClass, e);
504            }
505        }
506    
507        private void registerComponentAdapter(ClassLoadingPicoContainer container, Element element, ClassLoadingPicoContainer metaContainer) throws ClassNotFoundException, PicoCompositionException, MalformedURLException {
508            String className = element.getAttribute(CLASS);
509            if (notSet(className)) {
510                throw new ScriptedPicoContainerMarkupException("'" + CLASS + "' attribute not specified for " + element.getNodeName());
511            }
512            Class<?> implementationClass = getClassLoader().loadClass(className);
513            Object key = element.getAttribute(KEY);
514            String classKey = element.getAttribute(CLASS_NAME_KEY);
515            if (notSet(key)) {
516                if (!notSet(classKey)) {
517                    key = getClassLoader().loadClass(classKey);
518                } else {
519                    key = implementationClass;
520                }
521            }
522            Parameter[] parameters = createChildParameters(container, element);
523            ComponentFactory componentFactory = createComponentFactory(element.getAttribute(FACTORY), metaContainer);
524    
525            container.as(Characteristics.NONE).addAdapter(componentFactory.createComponentAdapter(new NullComponentMonitor(), new NullLifecycleStrategy(), new Properties(), key, implementationClass, parameters));
526        }
527    
528        private ComponentFactory createComponentFactory(String factoryName, ClassLoadingPicoContainer metaContainer) throws PicoCompositionException {
529            if ( notSet(factoryName)) {
530                return new Caching().wrap(new ConstructorInjection());
531            }
532            final Serializable key;
533            if (metaContainer.getComponentAdapter(factoryName) != null) {
534                key = factoryName;
535            } else {
536                metaContainer.addComponent(ComponentFactory.class, new ClassName(factoryName));
537                key = ComponentFactory.class;
538            }
539            return (ComponentFactory) metaContainer.getComponent(key);
540        }
541    
542    
543        private boolean notSet(Object string) {
544            return string == null || string.equals(EMPTY);
545        }
546    
547        private boolean boolValue(String string, boolean dft) {
548            if (notSet(string)) {
549                return dft;
550            }
551            boolean aBoolean = Boolean.valueOf(string).booleanValue();
552            return aBoolean;
553        }
554    
555    
556    }