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