    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&oslash;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    }