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 }