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 }