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 James Strachan                                           *
009     *****************************************************************************/
010    
011    package org.nanocontainer.script.groovy.buildernodes;
012    
013    import java.util.Map;
014    
015    import org.nanocontainer.NanoContainer;
016    import org.picocontainer.MutablePicoContainer;
017    import org.nanocontainer.script.NanoContainerMarkupException;
018    import java.util.Iterator;
019    import org.codehaus.groovy.runtime.InvokerHelper;
020    
021    /**
022     * Creates on-the-spot Javabeans configurations and registers the result with
023     * the container via pico.registerCompoenntInstance.
024     * @author James Strachan
025     * @author Paul Hammant
026     * @author Aslak Hellesøy
027     * @author Michael Rimov
028     * @author Mauro Talevi
029     * @version $Revision: 2695 $
030     */
031    public class BeanNode extends AbstractBuilderNode {
032    
033        /**
034         * The name of the node we're handling.
035         */
036        public static final String NODE_NAME = "bean";
037    
038        /**
039         * Bean class attribute.
040         */
041        public static final String BEAN_CLASS = "beanClass";
042    
043    
044        /**
045         * Default constructor.
046         */
047        public BeanNode() {
048            super(NODE_NAME);
049        }
050    
051        public Object createNewNode(Object current, Map attributes) {
052            MutablePicoContainer pico = ((NanoContainer) current).getPico();
053            Object bean = createBean(attributes);
054            pico.registerComponentInstance(bean);
055            return bean;
056        }
057    
058    
059        /**
060         * Instantiates the bean and sets the appropriate attributes.  It then
061         * @param attributes Map
062         * @return Object resulting JavaBean.
063         */
064        protected Object createBean(final Map attributes) {
065            Class type = (Class) attributes.remove(BEAN_CLASS);
066            if (type == null) {
067                throw new NanoContainerMarkupException("Bean must have a beanClass attribute");
068            }
069            try {
070                Object bean = type.newInstance();
071                // now let's set the properties on the bean
072                for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
073                    Map.Entry entry = (Map.Entry) iter.next();
074                    String name = entry.getKey().toString();
075                    Object value = entry.getValue();
076                    InvokerHelper.setProperty(bean, name, value);
077                }
078                return bean;
079            } catch (IllegalAccessException e) {
080                throw new NanoContainerMarkupException("Failed to create bean of type '" + type + "'. Reason: " + e, e);
081            } catch (InstantiationException e) {
082                throw new NanoContainerMarkupException("Failed to create bean of type " + type + "'. Reason: " + e, e);
083            }
084        }
085    
086        /**
087         * {@inheritDoc}
088         * <p>This version only checks for 'beanClass' and lets all other attributes
089         * through (since they become property values)</p>
090         * @param specifiedAttributes Map
091         * @throws NanoContainerMarkupException
092         */
093        public void validateScriptedAttributes(Map specifiedAttributes) throws NanoContainerMarkupException {
094            if (!specifiedAttributes.containsKey(BEAN_CLASS)) {
095                throw new NanoContainerMarkupException("Attribute " + BEAN_CLASS + " is required.");
096            }
097    
098            //Assume all other attributes
099        }
100    }