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 Aslak Hellesoy and Paul Hammant *
009 *****************************************************************************/
010
011 package org.nanocontainer;
012
013 import java.net.URL;
014 import java.security.AccessController;
015 import java.security.PermissionCollection;
016 import java.security.PrivilegedAction;
017 import java.util.ArrayList;
018 import java.util.HashMap;
019 import java.util.List;
020 import java.util.Map;
021
022 import org.nanocontainer.script.NanoContainerMarkupException;
023 import org.picocontainer.ComponentAdapter;
024 import org.picocontainer.MutablePicoContainer;
025 import org.picocontainer.Parameter;
026 import org.picocontainer.PicoIntrospectionException;
027 import org.picocontainer.PicoRegistrationException;
028 import org.picocontainer.defaults.BeanPropertyComponentAdapter;
029 import org.picocontainer.defaults.ConstantParameter;
030 import org.picocontainer.defaults.CustomPermissionsURLClassLoader;
031 import org.picocontainer.defaults.DefaultPicoContainer;
032
033 /**
034 * The default implementation of {@link NanoContainer}.
035 *
036 * @author Paul Hammant
037 * @author Aslak Hellesøy
038 */
039 public class DefaultNanoContainer implements NanoContainer {
040 private static final Map primitiveNameToBoxedName = new HashMap();
041 static {
042 primitiveNameToBoxedName.put("int", Integer.class.getName());
043 primitiveNameToBoxedName.put("byte", Byte.class.getName());
044 primitiveNameToBoxedName.put("short", Short.class.getName());
045 primitiveNameToBoxedName.put("long", Long.class.getName());
046 primitiveNameToBoxedName.put("float", Float.class.getName());
047 primitiveNameToBoxedName.put("double", Double.class.getName());
048 primitiveNameToBoxedName.put("boolean", Boolean.class.getName());
049 }
050
051 private final List classPathElements = new ArrayList();
052 private MutablePicoContainer picoContainer;
053 private final ClassLoader parentClassLoader;
054
055 private ClassLoader componentClassLoader;
056 private boolean componentClassLoaderLocked;
057
058 private static String getClassName(String primitiveOrClass) {
059 String fromMap = (String) primitiveNameToBoxedName.get(primitiveOrClass);
060 return fromMap != null ? fromMap : primitiveOrClass;
061 }
062
063 public DefaultNanoContainer(ClassLoader parentClassLoader, MutablePicoContainer picoContainer) {
064 this.parentClassLoader = parentClassLoader;
065 if (picoContainer == null) {
066 throw new NullPointerException("picoContainer");
067 }
068 this.picoContainer = picoContainer;
069 }
070
071 public DefaultNanoContainer(ClassLoader parentClassLoader) {
072 this(parentClassLoader, new DefaultPicoContainer());
073 }
074
075 public DefaultNanoContainer(MutablePicoContainer picoContainer) {
076 this(Thread.currentThread().getContextClassLoader(), picoContainer);
077 }
078
079 public DefaultNanoContainer(NanoContainer parent) {
080 this(parent.getComponentClassLoader(), new DefaultPicoContainer(parent.getPico()));
081 }
082
083 /**
084 * Beware - no parent container and no parent classloader.
085 */
086 public DefaultNanoContainer() {
087 this(Thread.currentThread().getContextClassLoader(), new DefaultPicoContainer());
088 }
089
090 public ComponentAdapter registerComponentImplementation(String componentImplementationClassName) throws PicoRegistrationException, ClassNotFoundException, PicoIntrospectionException {
091 return picoContainer.registerComponentImplementation(loadClass(componentImplementationClassName));
092 }
093
094 public ComponentAdapter registerComponentImplementation(Object key, String componentImplementationClassName) throws ClassNotFoundException {
095 Class componentImplementation = loadClass(componentImplementationClassName);
096 if (key instanceof ClassNameKey) {
097 key = loadClass(((ClassNameKey) key).getClassName());
098 }
099 return picoContainer.registerComponentImplementation(key, componentImplementation);
100 }
101
102
103 public ComponentAdapter registerComponentImplementation(Object key, String componentImplementationClassName, Parameter[] parameters) throws ClassNotFoundException {
104 Class componentImplementation = loadClass(componentImplementationClassName);
105 if (key instanceof ClassNameKey) {
106 key = loadClass(((ClassNameKey) key).getClassName());
107
108 }
109 return picoContainer.registerComponentImplementation(key, componentImplementation, parameters);
110 }
111
112 public ComponentAdapter registerComponentImplementation(Object key,
113 String componentImplementationClassName,
114 String[] parameterTypesAsString,
115 String[] parameterValuesAsString) throws PicoRegistrationException, ClassNotFoundException, PicoIntrospectionException {
116 Class componentImplementation = getComponentClassLoader().loadClass(componentImplementationClassName);
117 if (key instanceof ClassNameKey) {
118 key = loadClass(((ClassNameKey) key).getClassName());
119
120 }
121 return registerComponentImplementation(parameterTypesAsString, parameterValuesAsString, key, componentImplementation);
122 }
123
124 public ComponentAdapter registerComponentImplementation(String componentImplementationClassName,
125 String[] parameterTypesAsString,
126 String[] parameterValuesAsString) throws PicoRegistrationException, ClassNotFoundException, PicoIntrospectionException {
127 Class componentImplementation = getComponentClassLoader().loadClass(componentImplementationClassName);
128 return registerComponentImplementation(parameterTypesAsString, parameterValuesAsString, componentImplementation, componentImplementation);
129 }
130
131 private ComponentAdapter registerComponentImplementation(String[] parameterTypesAsString, String[] parameterValuesAsString, Object key, Class componentImplementation) throws ClassNotFoundException {
132 Parameter[] parameters = new Parameter[parameterTypesAsString.length];
133 for (int i = 0; i < parameters.length; i++) {
134 Object value = BeanPropertyComponentAdapter.convert(parameterTypesAsString[i], parameterValuesAsString[i], getComponentClassLoader());
135 parameters[i] = new ConstantParameter(value);
136 }
137 return picoContainer.registerComponentImplementation(key, componentImplementation, parameters);
138 }
139
140 private Class loadClass(final String className) throws ClassNotFoundException {
141 ClassLoader classLoader = getComponentClassLoader();
142 String cn = getClassName(className);
143 return classLoader.loadClass(cn);
144 }
145
146 public ClassPathElement addClassLoaderURL(URL url) {
147 if (componentClassLoaderLocked) throw new IllegalStateException("ClassLoader URLs cannot be added once this instance is locked");
148
149 ClassPathElement classPathElement = new ClassPathElement(url);
150 classPathElements.add(classPathElement);
151 return classPathElement;
152 }
153
154 public ClassLoader getComponentClassLoader() {
155 if (componentClassLoader == null) {
156 componentClassLoaderLocked = true;
157 componentClassLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
158 public Object run() {
159 return new CustomPermissionsURLClassLoader(getURLs(classPathElements), makePermissions(), parentClassLoader);
160 }
161 });
162 }
163 return componentClassLoader;
164 }
165
166 public MutablePicoContainer getPico() {
167 return picoContainer;
168 }
169
170 private Map makePermissions() {
171 Map permissionsMap = new HashMap();
172 for (int i = 0; i < classPathElements.size(); i++) {
173 ClassPathElement cpe = (ClassPathElement) classPathElements.get(i);
174 PermissionCollection permissionCollection = cpe.getPermissionCollection();
175 permissionsMap.put(cpe.getUrl(), permissionCollection);
176 }
177 return permissionsMap;
178 }
179
180 private URL[] getURLs(List classPathElemelements) {
181 final URL[] urls = new URL[classPathElemelements.size()];
182 for(int i = 0; i < urls.length; i++) {
183 urls[i] = ((ClassPathElement) classPathElemelements.get(i)).getUrl();
184 }
185 return urls;
186 }
187
188 public Object getComponentInstanceOfType(String componentType) {
189 try {
190 Class compType = getComponentClassLoader().loadClass(componentType);
191 return picoContainer.getComponentInstanceOfType(compType);
192 } catch (ClassNotFoundException e) {
193 throw new NanoContainerMarkupException("Can't resolve class as type '" + componentType + "'");
194 }
195 }
196
197 public MutablePicoContainer addDecoratingPicoContainer(Class picoContainerClass) {
198 DefaultPicoContainer pico = new DefaultPicoContainer();
199 pico.registerComponentImplementation(MutablePicoContainer.class, picoContainerClass, new Parameter[] { new ConstantParameter(picoContainer) });
200 picoContainer = (MutablePicoContainer) pico.getComponentInstanceOfType(MutablePicoContainer.class);
201 return picoContainer;
202 }
203
204 }