    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    import org.nanocontainer.NanoContainer;
    015    import org.nanocontainer.script.NanoContainerMarkupException;
    016    import org.picocontainer.defaults.DefaultPicoContainer;
    017    import java.security.PrivilegedAction;
    018    import org.picocontainer.defaults.ComponentAdapterFactory;
    019    import java.security.AccessController;
    020    import org.picocontainer.defaults.DefaultComponentAdapterFactory;
    021    import org.picocontainer.MutablePicoContainer;
    022    import org.picocontainer.PicoContainer;
    023    import org.nanocontainer.DefaultNanoContainer;
    024    import org.nanocontainer.script.NodeBuilderDecorationDelegate;
    025    import org.picocontainer.ComponentMonitor;
    026    import org.picocontainer.defaults.DelegatingComponentMonitor;
    027    import org.picocontainer.defaults.ComponentMonitorStrategy;
    028
    029    /**
    030     * Creates a new NanoContainer node.  There may or may not be a parent
    031     * container involved.
    032     * @author James Strachan
    033     * @author Paul Hammant
    034     * @author Aslak Helles&oslash;y
    035     * @author Michael Rimov
    036     * @author Mauro Talevi
    037     * @version $Revision: 2695 $
    038     */
    039    public class ChildContainerNode extends AbstractBuilderNode {
    040
    041        /**
    042         * Node name.
    043         */
    044        public static final String NODE_NAME = "container";
    045
    046        /**
    047         * Supported Attribute: 'class'  Reference to a classname of the container
    048         * to use.
    049         */
    050        private static final String CLASS = "class";
    051
    052        /**
    053         * The node decoration delegate.
    054         */
    055        private final NodeBuilderDecorationDelegate decorationDelegate;
    056
    057        /**
    058         * Attribute: 'componentAdapterFactory' a reference to an instance of a
    059         * component adapter factory.
    060         */
    061        private static final String COMPONENT_ADAPTER_FACTORY = "componentAdapterFactory";
    062
    063        /**
    064         * Attribute: 'componentMonitor' a reference to an instance of a component monitor.
    065         */
    066        private static final String COMPONENT_MONITOR = "componentMonitor";
    067
    068
    069        /**
    070         * Attribute that exists in test cases, but not necessarily used?
    071         *
    072         */
    073        private static final String SCOPE = "scope";
    074
    075
    076        /**
    077         * Attribute: 'parent'  a reference to the parent for this new container.
    078         */
    079        private static final String PARENT = "parent";
    080
    081
    082        /**
    083         * Constructs a child container node.  It requires a <tt>NodeBuilderDecorationDelegate</tt>
    084         * for construction.
    085         * @param delegate NodeBuilderDecorationDelegate
    086         */
    087        public ChildContainerNode(NodeBuilderDecorationDelegate delegate) {
    088            super(NODE_NAME);
    089            decorationDelegate = delegate;
    090
    091            this.addAttribute(CLASS)
    092                .addAttribute(COMPONENT_ADAPTER_FACTORY)
    093                .addAttribute(COMPONENT_MONITOR)
    094                .addAttribute(PARENT)
    095                .addAttribute(SCOPE);
    096
    097
    098        }
    099
    100        /**
    101         * Creates a new container.  There may or may not be a parent to this container.
    102         * Supported attributes are
    103         * <p>{@inheritDoc}</p>
    104         * @param current NanoContainer
    105         * @param attributes Map
    106         * @return Object
    107         * @throws NanoContainerMarkupException
    108         */
    109        public Object createNewNode(Object current, Map attributes) throws
    110            NanoContainerMarkupException {
    111
    112            return createChildContainer(attributes,(NanoContainer) current);
    113        }
    114
    115        /**
    116         * Retrieve the decoration delegate.
    117         * @return NodeBuilderDecorationDelegate
    118         */
    119        private NodeBuilderDecorationDelegate getDecorationDelegate() {
    120            return decorationDelegate;
    121        }
    122
    123
    124
    125        /**
    126         * Creates a new container.  There may or may not be a parent to this container.
    127         * Supported attributes are:
    128         * <ul>
    129         *  <li><tt>componentAdapterFactory</tt>: The ComponentAdapterFactory used for new container</li>
    130         *  <li><tt>componentMonitor</tt>: The ComponentMonitor used for new container</li>
    131         * </ul>
    132         * @param attributes Map Attributes defined by the builder in the script.
    133         * @param parent The parent container
    134         * @return The NanoContainer
    135         */
    136        protected NanoContainer createChildContainer(Map attributes, NanoContainer parent) {
    137
    138            ClassLoader parentClassLoader = null;
    139            MutablePicoContainer childContainer = null;
    140            if (parent != null) {
    141                parentClassLoader = parent.getComponentClassLoader();
    142                if ( isAttribute(attributes, COMPONENT_ADAPTER_FACTORY) ) {
    143                    ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(attributes);
    144                    childContainer = new DefaultPicoContainer(
    145                            getDecorationDelegate().decorate(componentAdapterFactory, attributes), parent.getPico());
    146                    if ( isAttribute(attributes, COMPONENT_MONITOR) ) {
    147                        changeComponentMonitor(childContainer, createComponentMonitor(attributes));
    148                    }
    149                    parent.getPico().addChildContainer(childContainer);
    150                } else if ( isAttribute(attributes, COMPONENT_MONITOR) ) {
    151                    ComponentAdapterFactory componentAdapterFactory = new DefaultComponentAdapterFactory(
    152                                                        createComponentMonitor(attributes));
    153                    childContainer = new DefaultPicoContainer(
    154                            getDecorationDelegate().decorate(componentAdapterFactory, attributes), parent.getPico());
    155                } else {
    156                    childContainer = parent.getPico().makeChildContainer();
    157                }
    158            } else {
    159                parentClassLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
    160                    public Object run() {
    161                        return PicoContainer.class.getClassLoader();
    162                    }
    163                });
    164                ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(attributes);
    165                childContainer = new DefaultPicoContainer(
    166                        getDecorationDelegate().decorate(componentAdapterFactory, attributes));
    167                if ( isAttribute(attributes, COMPONENT_MONITOR) ) {
    168                    changeComponentMonitor(childContainer, createComponentMonitor(attributes));
    169                }
    170            }
    171
    172            MutablePicoContainer decoratedPico = getDecorationDelegate().decorate(childContainer);
    173            if ( isAttribute(attributes, CLASS) )  {
    174                Class clazz = (Class) attributes.get(CLASS);
    175                return createNanoContainer(clazz, decoratedPico, parentClassLoader);
    176            } else {
    177                return new DefaultNanoContainer(parentClassLoader, decoratedPico);
    178            }
    179        }
    180
    181        private void changeComponentMonitor(MutablePicoContainer childContainer, ComponentMonitor monitor) {
    182            if ( childContainer instanceof ComponentMonitorStrategy ){
    183                ((ComponentMonitorStrategy)childContainer).changeMonitor(monitor);
    184            }
    185        }
    186
    187        private NanoContainer createNanoContainer(Class clazz, MutablePicoContainer decoratedPico, ClassLoader parentClassLoader) {
    188            DefaultPicoContainer instantiatingContainer = new DefaultPicoContainer();
    189            instantiatingContainer.registerComponentInstance(ClassLoader.class, parentClassLoader);
    190            instantiatingContainer.registerComponentInstance(MutablePicoContainer.class, decoratedPico);
    191            instantiatingContainer.registerComponentImplementation(NanoContainer.class, clazz);
    192            Object componentInstance = instantiatingContainer.getComponentInstance(NanoContainer.class);
    193            return (NanoContainer) componentInstance;
    194        }
    195
    196        private ComponentAdapterFactory createComponentAdapterFactory(Map attributes) {
    197            final ComponentAdapterFactory factory = (ComponentAdapterFactory) attributes.remove(COMPONENT_ADAPTER_FACTORY);
    198            if ( factory == null ){
    199                return new DefaultComponentAdapterFactory();
    200            }
    201            return factory;
    202        }
    203
    204        private ComponentMonitor createComponentMonitor(Map attributes) {
    205            final ComponentMonitor monitor = (ComponentMonitor) attributes.remove(COMPONENT_MONITOR);
    206            if ( monitor == null ){
    207                return new DelegatingComponentMonitor();
    208            }
    209            return monitor;
    210        }
    211
    212
    213    }