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 }