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.Map; 011 012 import org.picocontainer.PicoContainer; 013 import org.picocontainer.script.ScriptedPicoContainerMarkupException; 014 import org.picocontainer.classname.ClassLoadingPicoContainer; 015 016 /** 017 * Sometimes it is worthwhile to split apart node building into functions. For 018 * example, you might want to group adding the domain object repositories (DAOs) 019 * into a single function to make your composition script easier to maintain. 020 * <p> 021 * Unfortunately, normally this is not allowed under normal builder rules. If 022 * you wish to separate code you must revert to standard picocontainer calling 023 * systax. 024 * </p> 025 * <p> 026 * This node corrects that deficiency. 027 * </p> 028 * <p> 029 * With it you can perform: <code><pre> 030 * pico = builder.container(parent:parent) { 031 * component(....) 032 * //... 033 * } 034 * <br/> 035 * // 036 * <em> 037 * Now add more to pico. 038 * </em> 039 * builder.append(container: pico) { 040 * component(....) 041 * //... 042 * } 043 * </pre></code> 044 * </p> 045 * 046 * @author Michael Rimov 047 */ 048 @SuppressWarnings("serial") 049 public class AppendContainerNode extends AbstractBuilderNode { 050 /** 051 * Node name. 052 */ 053 public static final String NODE_NAME = "append"; 054 055 /** 056 * Supported Attribute (Required): 'container.' Reference to the container 057 * we are going to append to. 058 */ 059 public static final String CONTAINER = "container"; 060 061 /** 062 * Constructs an append container node. 063 */ 064 public AppendContainerNode() { 065 super(NODE_NAME); 066 } 067 068 /** 069 * Returns the container passed in as the "container" attribute. 070 * 071 * @param current the current Object, unused. 072 * @param attributes the Map of attributes, which must have the container 073 * attribute defined. 074 * @return Object the passed in node builder. 075 * @throws ScriptedPicoContainerMarkupException if the container attribute 076 * is not supplied. 077 * @throws ClassCastException if the container node specified is not a 078 * ScriptedPicoContainer or PicoContainer 079 */ 080 public Object createNewNode(final Object current, final Map<String, Object> attributes) 081 throws ScriptedPicoContainerMarkupException, ClassCastException { 082 if (!isAttribute(attributes, CONTAINER)) { 083 throw new ScriptedPicoContainerMarkupException(NODE_NAME + " must have a container attribute"); 084 } 085 086 Object attributeValue = attributes.get(CONTAINER); 087 if (!(attributeValue instanceof ClassLoadingPicoContainer) && !(attributeValue instanceof PicoContainer)) { 088 throw new ClassCastException(attributeValue.toString() 089 + " must be a derivative of ScriptedPicoContainer or PicoContainer. Got: " 090 + attributeValue.getClass().getName() + " instead."); 091 } 092 return attributeValue; 093 } 094 095 }