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