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