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    }