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 }