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    }