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