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 }