001    /*******************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved.
003     * ---------------------------------------------------------------------------
004     * The software in this package is published under the terms of the BSD style
005     * license a copy of which has been included with this distribution in the
006     * LICENSE.txt file.
007     ******************************************************************************/
008    package org.picocontainer.script.groovy.nodes;
009    
010    import java.util.List;
011    import java.util.Map;
012    import java.util.Properties;
013    
014    import org.picocontainer.Parameter;
015    import org.picocontainer.parameters.ConstantParameter;
016    import org.picocontainer.script.NodeBuilderDecorator;
017    import org.picocontainer.classname.ClassLoadingPicoContainer;
018    import org.picocontainer.script.util.ComponentElementHelper;
019    
020    /**
021     * Creates a component node
022     * 
023     * @author James Strachan
024     * @author Paul Hammant
025     * @author Aslak Hellesøy
026     * @author Michael Rimov
027     * @author Mauro Talevi
028     */
029    @SuppressWarnings("serial")
030    public class ComponentNode extends AbstractBuilderNode {
031    
032        public static final String NODE_NAME = "component";
033    
034        /**
035         * Attributes 'key'
036         */
037        public static final String KEY = "key";
038    
039        /**
040         * Class attribute.
041         */
042        private static final String CLASS = "class";
043    
044        /**
045         * Class Name Key Attribute.
046         */
047        private static final String CLASS_NAME_KEY = "classNameKey";
048    
049        /**
050         * Instance attribute name.
051         */
052        private static final String INSTANCE = "instance";
053    
054        /**
055         * Parameters attribute name.
056         */
057        private static final String PARAMETERS = "parameters";
058    
059        /**
060         * Properties attribute name.
061         */
062        private static final String PROPERTIES = "properties";
063    
064        private final NodeBuilderDecorator decorator;
065    
066        public ComponentNode(NodeBuilderDecorator decorator) {
067            super(NODE_NAME);
068            this.decorator = decorator;
069            // Supported attributes.
070            this.addAttribute(KEY).addAttribute(CLASS).addAttribute(CLASS_NAME_KEY).addAttribute(INSTANCE).addAttribute(
071                    PARAMETERS).addAttribute(PROPERTIES);
072        }
073    
074        /**
075         * Execute the handler for the given node builder.
076         * 
077         * @param current The current node.
078         * @param attributes Map attributes specified in the groovy script for the
079         *            builder node.
080         * @return Object
081         */
082        public Object createNewNode(final Object current, final Map<String, Object> attributes) {
083            decorator.rememberComponentKey(attributes);
084            Object key = attributes.remove(KEY);
085            Object classNameKey = attributes.remove(CLASS_NAME_KEY);
086            Object classValue = attributes.remove(CLASS);
087            Object instance = attributes.remove(INSTANCE);
088            Object parameters = attributes.remove(PARAMETERS);
089            Object properties = attributes.remove(PROPERTIES);
090    
091            return ComponentElementHelper.makeComponent(classNameKey, key, getParameters(parameters), classValue,
092                    (ClassLoadingPicoContainer) current, instance, getProperties(properties));
093        }
094    
095        @SuppressWarnings("unchecked")
096        private static Parameter[] getParameters(Object params) {
097            if (params == null) {
098                return null;
099            }
100    
101            if (params instanceof Parameter[]) {
102                return (Parameter[]) params;
103            }
104    
105            if (!(params instanceof List)) {
106                throw new IllegalArgumentException("Parameters may only be of type List or Parameter Array");
107            }
108    
109            List<Parameter> list = (List<Parameter>) params;
110    
111            int n = list.size();
112            Parameter[] parameters = new Parameter[n];
113            for (int i = 0; i < n; ++i) {
114                parameters[i] = toParameter(list.get(i));
115            }
116            return parameters;
117        }
118    
119        private static Parameter toParameter(Object obj) {
120            return obj instanceof Parameter ? (Parameter) obj : new ConstantParameter(obj);
121        }
122    
123        @SuppressWarnings("unchecked")
124        private static Properties[] getProperties(Object props) {
125            if (props == null) {
126                return new Properties[0];
127            }
128            if (!(props instanceof List)) {
129                throw new IllegalArgumentException("Properties may only be of type List");
130            }
131    
132            List<Properties> list = (List<Properties>) props;
133            return list.toArray(new Properties[list.size()]);
134        }
135    
136    }