    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 Paul Hammant                                             *
    009     *****************************************************************************/
    010
    011    package org.nanocontainer.reflection;
    012
    013    import java.io.Serializable;
    014    import java.net.URL;
    015    import java.util.Collection;
    016    import java.util.HashMap;
    017    import java.util.Iterator;
    018    import java.util.Map;
    019    import org.nanocontainer.ClassPathElement;
    020    import org.nanocontainer.DefaultNanoContainer;
    021    import org.nanocontainer.NanoContainer;
    022    import org.nanocontainer.NanoPicoContainer;
    023    import org.picocontainer.ComponentAdapter;
    024    import org.picocontainer.MutablePicoContainer;
    025    import org.picocontainer.Parameter;
    026    import org.picocontainer.PicoContainer;
    027    import org.picocontainer.PicoException;
    028    import org.picocontainer.PicoIntrospectionException;
    029    import org.picocontainer.PicoRegistrationException;
    030    import org.picocontainer.alternatives.AbstractDelegatingMutablePicoContainer;
    031
    032    /**
    033     * A base class for NanoPicoContainers. As well as the functionality indicated by the interface it
    034     * implements, extenders of this class will have named child component capability.
    035     *
    036     * @author Paul Hammant
    037     * @version $Revision: 2964 $
    038     */
    039    public abstract class AbstractNanoPicoContainer extends AbstractDelegatingMutablePicoContainer implements NanoPicoContainer, Serializable {
    040
    041        protected Map namedChildContainers = new HashMap();
    042
    043        // Serializable cannot be cascaded into DefaultNanoContainer's referenced classes
    044        // need to implement custom Externalisable regime.
    045        protected transient NanoContainer container;
    046
    047
    048        protected AbstractNanoPicoContainer(MutablePicoContainer delegate, ClassLoader classLoader) {
    049            super(delegate);
    050            container = new DefaultNanoContainer(classLoader, delegate);
    051        }
    052
    053        public final Object getComponentInstance(Object componentKey) throws PicoException {
    054
    055            Object instance = getDelegate().getComponentInstance(componentKey);
    056
    057            if (instance != null) {
    058                return instance;
    059            }
    060
    061            ComponentAdapter componentAdapter = null;
    062            if (componentKey.toString().startsWith("*")) {
    063                String candidateClassName = componentKey.toString().substring(1);
    064                Collection cas = getComponentAdapters();
    065                for (Iterator it = cas.iterator(); it.hasNext();) {
    066                    ComponentAdapter ca = (ComponentAdapter) it.next();
    067                    Object key = ca.getComponentKey();
    068                    if (key instanceof Class && candidateClassName.equals(((Class) key).getName())) {
    069                        componentAdapter = ca;
    070                        break;
    071                    }
    072                }
    073            }
    074            if (componentAdapter != null) {
    075                return componentAdapter.getComponentInstance(this);
    076            } else {
    077                return getComponentInstanceFromChildren(componentKey);
    078            }
    079        }
    080
    081        private Object getComponentInstanceFromChildren(Object componentKey) {
    082            String componentKeyPath = componentKey.toString();
    083            int ix = componentKeyPath.indexOf('/');
    084            if (ix != -1) {
    085                String firstElement = componentKeyPath.substring(0, ix);
    086                String remainder = componentKeyPath.substring(ix + 1, componentKeyPath.length());
    087                Object o = getNamedContainers().get(firstElement);
    088                if (o != null) {
    089                    MutablePicoContainer child = (MutablePicoContainer) o;
    090                    return child.getComponentInstance(remainder);
    091                }
    092            }
    093            return null;
    094        }
    095
    096        public final MutablePicoContainer makeChildContainer() {
    097            return makeChildContainer("containers" + namedChildContainers.size());
    098        }
    099
    100        /**
    101         * Makes a child container with the same basic characteristics of <tt>this</tt>
    102         * object (ComponentAdapterFactory, PicoContainer type, LifecycleManager, etc)
    103         * @param name the name of the child container
    104         * @return The child MutablePicoContainer
    105         */
    106        public MutablePicoContainer makeChildContainer(String name) {
    107            AbstractNanoPicoContainer child = createChildContainer();
    108            MutablePicoContainer parentDelegate = getDelegate();
    109            parentDelegate.removeChildContainer(child.getDelegate());
    110            parentDelegate.addChildContainer(child);
    111            namedChildContainers.put(name, child);
    112            return child;
    113        }
    114
    115        protected abstract AbstractNanoPicoContainer createChildContainer();
    116
    117        public boolean removeChildContainer(PicoContainer child) {
    118            boolean result = getDelegate().removeChildContainer(child);
    119            Iterator children = namedChildContainers.entrySet().iterator();
    120            while (children.hasNext()) {
    121                Map.Entry e = (Map.Entry) children.next();
    122                PicoContainer pc = (PicoContainer) e.getValue();
    123                if (pc == child) {
    124                    children.remove();
    125                }
    126            }
    127            return result;
    128        }
    129
    130        protected final Map getNamedContainers() {
    131            return namedChildContainers;
    132        }
    133
    134        public Object getComponentInstanceOfType(String componentType) {
    135            return container.getComponentInstanceOfType(componentType);
    136        }
    137
    138        public MutablePicoContainer addDecoratingPicoContainer(Class picoContainerClass) {
    139            return container.addDecoratingPicoContainer(picoContainerClass);
    140        }
    141
    142
    143        public ClassPathElement addClassLoaderURL(URL url) {
    144            return container.addClassLoaderURL(url);
    145        }
    146
    147        public ComponentAdapter registerComponentImplementation(String componentImplementationClassName) throws PicoRegistrationException, ClassNotFoundException, PicoIntrospectionException {
    148            return container.registerComponentImplementation(componentImplementationClassName);
    149        }
    150
    151        public ComponentAdapter registerComponentImplementation(Object key, String componentImplementationClassName) throws ClassNotFoundException {
    152            return container.registerComponentImplementation(key, componentImplementationClassName);
    153        }
    154
    155        public ComponentAdapter registerComponentImplementation(Object key, String componentImplementationClassName, Parameter[] parameters) throws ClassNotFoundException {
    156            return container.registerComponentImplementation(key, componentImplementationClassName, parameters);
    157        }
    158
    159        public ComponentAdapter registerComponentImplementation(Object key, String componentImplementationClassName, String[] parameterTypesAsString, String[] parameterValuesAsString) throws PicoRegistrationException, ClassNotFoundException, PicoIntrospectionException {
    160            return container.registerComponentImplementation(key, componentImplementationClassName, parameterTypesAsString, parameterValuesAsString);
    161        }
    162
    163        public ComponentAdapter registerComponentImplementation(String componentImplementationClassName, String[] parameterTypesAsString, String[] parameterValuesAsString) throws PicoRegistrationException, ClassNotFoundException, PicoIntrospectionException {
    164            return container.registerComponentImplementation(componentImplementationClassName, parameterTypesAsString, parameterValuesAsString);
    165        }
    166
    167
    168        //TODO Should this method be the NanoContainer interface only?
    169        public MutablePicoContainer getPico() {
    170            return this;
    171        }
    172
    173        public ClassLoader getComponentClassLoader() {
    174            return container.getComponentClassLoader();
    175        }
    176
    177        public boolean addChildContainer(PicoContainer child) {
    178            boolean result = getDelegate().addChildContainer(child);
    179
    180
    181            namedChildContainers.put("containers" + namedChildContainers.size(), child);
    182            return result;
    183        }
    184
    185        public void addChildContainer(String name, PicoContainer child) {
    186
    187            super.addChildContainer(child);
    188
    189            namedChildContainers.put(name, child);
    190        }
    191
    192    }