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     * &lt;br/&gt;
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 &quot;container&quot; 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    }