    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&oslash;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    }