001    /*****************************************************************************
002     * Copyright (C) PicoContainer 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.picocontainer.script.xml;
010    
011    import org.picocontainer.ComponentAdapter;
012    import org.picocontainer.PicoContainer;
013    import org.picocontainer.PicoClassNotFoundException;
014    import org.picocontainer.lifecycle.NullLifecycleStrategy;
015    import org.picocontainer.monitors.NullComponentMonitor;
016    import org.picocontainer.injectors.AdaptingInjection;
017    import org.picocontainer.behaviors.PropertyApplicator;
018    import org.picocontainer.ComponentFactory;
019    
020    import java.util.Properties;
021    
022    import org.w3c.dom.Element;
023    import org.w3c.dom.Node;
024    import org.w3c.dom.NodeList;
025    
026    /**
027     * Implementation of XMLComponentInstanceFactory that uses PropertyApplicator
028     * to create instances from DOM elements.
029     *
030     * @author Paul Hammant
031     * @author Marcos Tarruella
032     * @author Mauro Talevi
033     */
034    public class BeanComponentInstanceFactory implements XMLComponentInstanceFactory {
035        
036        private static final String NAME_ATTRIBUTE = "name";
037        
038        @SuppressWarnings("unchecked")
039        public Object makeInstance(PicoContainer pico, Element element, ClassLoader classLoader) {
040            String className = element.getNodeName();
041            Object instance;
042    
043            if (element.getChildNodes().getLength() == 1) {
044                instance = PropertyApplicator.convert(className, element.getFirstChild().getNodeValue(), classLoader);
045            } else {
046                PropertyApplicator propertyAdapter =
047                        new PropertyApplicator(createComponentAdapter(className, classLoader));
048                java.util.Properties properties = createProperties(element.getChildNodes());
049                propertyAdapter.setProperties(properties);
050                instance = propertyAdapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class);
051            }
052            return instance;
053        }
054    
055        @SuppressWarnings("unchecked")
056        private ComponentAdapter createComponentAdapter(String className, ClassLoader classLoader)  {
057            Class implementation = loadClass(classLoader, className);
058            ComponentFactory factory = new AdaptingInjection();
059            return factory.createComponentAdapter(new NullComponentMonitor(), new NullLifecycleStrategy(), new Properties(), className, implementation);
060        }
061    
062        private Class<?> loadClass(final ClassLoader classLoader, final String className) {
063            try {
064                return classLoader.loadClass(className);
065            } catch (ClassNotFoundException e) {
066                throw new PicoClassNotFoundException(className, e);
067            }
068        }
069    
070        private java.util.Properties createProperties(NodeList nodes) {
071            java.util.Properties properties = new java.util.Properties();
072            for (int i = 0; i < nodes.getLength(); i++) {
073                Node n = nodes.item(i);
074                if (n.getNodeType() == Node.ELEMENT_NODE) {
075                    String name = n.getNodeName();
076                    
077                    //Provide for a new 'name' attribute in properties.
078                    if (n.hasAttributes()) {
079                        String mappedName = n.getAttributes().getNamedItem(NAME_ATTRIBUTE).getNodeValue();
080                        if (mappedName != null) {
081                            name = mappedName;
082                        }
083                    }
084    
085                    String value = n.getFirstChild().getNodeValue();
086                    properties.setProperty(name, value);
087                }
088            }
089            return properties;
090        }
091    }