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     *****************************************************************************/
009    package org.nanocontainer.script.xml;
010    
011    import org.picocontainer.ComponentAdapter;
012    import org.picocontainer.Parameter;
013    import org.picocontainer.PicoContainer;
014    import org.picocontainer.defaults.BeanPropertyComponentAdapter;
015    import org.picocontainer.defaults.ComponentAdapterFactory;
016    import org.picocontainer.defaults.DefaultComponentAdapterFactory;
017    import org.w3c.dom.Element;
018    import org.w3c.dom.Node;
019    import org.w3c.dom.NodeList;
020    
021    import java.net.MalformedURLException;
022    import java.util.Properties;
023    
024    /**
025     * Implementation of XMLComponentInstanceFactory that uses BeanPropertyComponentAdapter
026     * to create instances from DOM elements.
027     *
028     * @author Paul Hammant
029     * @author Marcos Tarruella
030     * @author Mauro Talevi
031     */
032    public class BeanComponentInstanceFactory implements XMLComponentInstanceFactory {
033        
034        private static final String NAME_ATTRIBUTE = "name";
035        
036        public Object makeInstance(PicoContainer pico, Element element, ClassLoader classLoader) throws ClassNotFoundException, MalformedURLException {
037            String className = element.getNodeName();
038            Object instance = null;
039    
040            if (element.getChildNodes().getLength() == 1) {
041                instance = BeanPropertyComponentAdapter.convert(className, element.getFirstChild().getNodeValue(), classLoader);
042            } else {
043                BeanPropertyComponentAdapter propertyComponentAdapter =
044                        new BeanPropertyComponentAdapter(createComponentAdapter(className, classLoader));
045                Properties properties = createProperties(element.getChildNodes());
046                propertyComponentAdapter.setProperties(properties);
047                instance = propertyComponentAdapter.getComponentInstance(pico);
048            }
049            return instance;
050        }
051    
052        private ComponentAdapter createComponentAdapter(String className, ClassLoader classLoader) throws ClassNotFoundException {
053            Class implementation = classLoader.loadClass(className);
054            ComponentAdapterFactory factory = new DefaultComponentAdapterFactory();
055            return factory.createComponentAdapter(className, implementation, new Parameter[]{});
056        }
057    
058        private Properties createProperties(NodeList nodes) {
059            Properties properties = new Properties();
060            for (int i = 0; i < nodes.getLength(); i++) {
061                Node n = nodes.item(i);
062                if (n.getNodeType() == Node.ELEMENT_NODE) {
063                    String name = n.getNodeName();
064                    
065                    //Provide for a new 'name' attribute in properties.
066                    if (n.hasAttributes()) {
067                        String mappedName = n.getAttributes().getNamedItem(NAME_ATTRIBUTE).getNodeValue();
068                        if (mappedName != null) {
069                            name = mappedName;
070                        }
071                    }
072    
073                    String value = n.getFirstChild().getNodeValue();
074                    properties.setProperty(name, value);
075                }
076            }
077            return properties;
078        }
079    }