001 /******************************************************************************* 002 * Copyright (C) PicoContainer Organization. All rights reserved. 003 * --------------------------------------------------------------------------- 004 * The software in this package is published under the terms of the BSD style 005 * license a copy of which has been included with this distribution in the 006 * LICENSE.txt file. 007 ******************************************************************************/ 008 package org.picocontainer.classname; 009 010 import org.picocontainer.ComponentAdapter; 011 import org.picocontainer.ComponentFactory; 012 import org.picocontainer.ComponentMonitor; 013 import org.picocontainer.ComponentMonitorStrategy; 014 import org.picocontainer.LifecycleStrategy; 015 import org.picocontainer.MutablePicoContainer; 016 import org.picocontainer.Parameter; 017 import org.picocontainer.PicoClassNotFoundException; 018 import org.picocontainer.PicoContainer; 019 import org.picocontainer.PicoException; 020 import org.picocontainer.security.CustomPermissionsURLClassLoader; 021 import org.picocontainer.DefaultPicoContainer; 022 import org.picocontainer.PicoCompositionException; 023 import org.picocontainer.NameBinding; 024 import org.picocontainer.PicoVisitor; 025 import org.picocontainer.classname.ClassPathElement; 026 import org.picocontainer.classname.ClassLoadingPicoContainer; 027 import org.picocontainer.behaviors.Caching; 028 import org.picocontainer.containers.AbstractDelegatingMutablePicoContainer; 029 030 import java.lang.annotation.Annotation; 031 import java.lang.reflect.Type; 032 import java.net.URL; 033 import java.security.AccessController; 034 import java.security.PrivilegedAction; 035 import java.security.Permissions; 036 import java.util.ArrayList; 037 import java.util.Collection; 038 import java.util.HashMap; 039 import java.util.Iterator; 040 import java.util.List; 041 import java.util.Map; 042 import java.util.Properties; 043 044 /** 045 * Default implementation of ClassLoadingPicoContainer. 046 * 047 * @author Paul Hammant 048 * @author Mauro Talevi 049 * @author Michael Rimov 050 */ 051 @SuppressWarnings("serial") 052 public class DefaultClassLoadingPicoContainer extends AbstractDelegatingMutablePicoContainer implements 053 ClassLoadingPicoContainer, ComponentMonitorStrategy { 054 055 /** 056 * Conversion Map to allow for primitives to be boxed to Object types. 057 */ 058 private static final transient Map<String, String> primitiveNameToBoxedName = new HashMap<String, String>(); 059 060 static { 061 primitiveNameToBoxedName.put("int", Integer.class.getName()); 062 primitiveNameToBoxedName.put("byte", Byte.class.getName()); 063 primitiveNameToBoxedName.put("short", Short.class.getName()); 064 primitiveNameToBoxedName.put("long", Long.class.getName()); 065 primitiveNameToBoxedName.put("float", Float.class.getName()); 066 primitiveNameToBoxedName.put("double", Double.class.getName()); 067 primitiveNameToBoxedName.put("boolean", Boolean.class.getName()); 068 } 069 070 private final transient List<ClassPathElement> classPathElements = new ArrayList<ClassPathElement>(); 071 private final transient ClassLoader parentClassLoader; 072 073 private transient ClassLoader componentClassLoader; 074 private transient boolean componentClassLoaderLocked; 075 076 protected final Map<String, PicoContainer> namedChildContainers = new HashMap<String, PicoContainer>(); 077 078 public DefaultClassLoadingPicoContainer(ClassLoader classLoader, ComponentFactory componentFactory, PicoContainer parent) { 079 super(new DefaultPicoContainer(componentFactory, parent)); 080 parentClassLoader = classLoader; 081 } 082 083 public DefaultClassLoadingPicoContainer(ClassLoader classLoader, MutablePicoContainer delegate) { 084 super(delegate); 085 parentClassLoader = classLoader; 086 087 } 088 089 public DefaultClassLoadingPicoContainer(ClassLoader classLoader, PicoContainer parent, ComponentMonitor componentMonitor) { 090 super(new DefaultPicoContainer(new Caching(), parent)); 091 parentClassLoader = classLoader; 092 ((ComponentMonitorStrategy) getDelegate()).changeMonitor(componentMonitor); 093 } 094 095 public DefaultClassLoadingPicoContainer(ComponentFactory componentFactory) { 096 super(new DefaultPicoContainer(componentFactory, null)); 097 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader(); 098 } 099 100 101 public DefaultClassLoadingPicoContainer(PicoContainer parent) { 102 super(new DefaultPicoContainer(parent)); 103 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader(); 104 } 105 106 public DefaultClassLoadingPicoContainer(MutablePicoContainer delegate) { 107 super(delegate); 108 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader(); 109 } 110 111 public DefaultClassLoadingPicoContainer(ClassLoader classLoader) { 112 super(new DefaultPicoContainer()); 113 parentClassLoader = classLoader; 114 } 115 116 public DefaultClassLoadingPicoContainer() { 117 super(new DefaultPicoContainer()); 118 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader(); 119 } 120 121 public DefaultClassLoadingPicoContainer(ComponentFactory componentFactory, LifecycleStrategy lifecycleStrategy, 122 PicoContainer parent, ClassLoader cl, ComponentMonitor componentMonitor) { 123 124 super(new DefaultPicoContainer(componentFactory, lifecycleStrategy, parent, componentMonitor)); 125 parentClassLoader = (cl != null) ? cl : DefaultClassLoadingPicoContainer.class.getClassLoader(); 126 } 127 128 protected DefaultClassLoadingPicoContainer createChildContainer() { 129 MutablePicoContainer child = getDelegate().makeChildContainer(); 130 DefaultClassLoadingPicoContainer container = new DefaultClassLoadingPicoContainer(getComponentClassLoader(), child); 131 container.changeMonitor(currentMonitor()); 132 return container; 133 } 134 135 /** 136 * Propagates the monitor change down the delegate chain if a delegate that implements ComponentMonitorStrategy 137 * exists. Because of the ComponentMonitorStrategy API, not all delegates can have their API changed. If 138 * a delegate implementing ComponentMonitorStrategy cannot be found, an exception is thrown. 139 * @throws IllegalStateException if no delegate can be found that implements ComponentMonitorStrategy. 140 * @param monitor the monitor to swap. 141 */ 142 public void changeMonitor(ComponentMonitor monitor) { 143 144 MutablePicoContainer picoDelegate = getDelegate(); 145 while (picoDelegate != null) { 146 if (picoDelegate instanceof ComponentMonitorStrategy) { 147 ((ComponentMonitorStrategy)picoDelegate).changeMonitor(monitor); 148 return; 149 } 150 151 if (picoDelegate instanceof AbstractDelegatingMutablePicoContainer) { 152 picoDelegate = ((AbstractDelegatingMutablePicoContainer)picoDelegate).getDelegate(); 153 } else { 154 break; 155 } 156 } 157 158 throw new IllegalStateException("Could not find delegate picocontainer that implemented ComponentMonitorStrategy"); 159 160 161 } 162 163 public ComponentMonitor currentMonitor() { 164 MutablePicoContainer picoDelegate = getDelegate(); 165 while (picoDelegate != null) { 166 if (picoDelegate instanceof ComponentMonitorStrategy) { 167 return ((ComponentMonitorStrategy)picoDelegate).currentMonitor(); 168 } 169 170 if (picoDelegate instanceof AbstractDelegatingMutablePicoContainer) { 171 picoDelegate = ((AbstractDelegatingMutablePicoContainer)picoDelegate).getDelegate(); 172 } else { 173 break; 174 } 175 } 176 177 throw new IllegalStateException("Could not find delegate picocontainer that implemented ComponentMonitorStrategy"); 178 } 179 180 public final Object getComponent(Object componentKeyOrType) throws PicoException { 181 182 if (componentKeyOrType instanceof ClassName) { 183 componentKeyOrType = loadClass(componentKeyOrType.toString()); 184 } 185 186 Object instance = getDelegate().getComponent(componentKeyOrType); 187 188 if (instance != null) { 189 return instance; 190 } 191 192 ComponentAdapter<?> componentAdapter = null; 193 if (componentKeyOrType.toString().startsWith("*")) { 194 String candidateClassName = componentKeyOrType.toString().substring(1); 195 Collection<ComponentAdapter<?>> cas = getComponentAdapters(); 196 for (ComponentAdapter<?> ca : cas) { 197 Object key = ca.getComponentKey(); 198 if (key instanceof Class && candidateClassName.equals(((Class<?>) key).getName())) { 199 componentAdapter = ca; 200 break; 201 } 202 } 203 } 204 if (componentAdapter != null) { 205 return componentAdapter.getComponentInstance(this, ComponentAdapter.NOTHING.class); 206 } else { 207 return getComponentInstanceFromChildren(componentKeyOrType); 208 } 209 } 210 211 private Object getComponentInstanceFromChildren(Object componentKey) { 212 String componentKeyPath = componentKey.toString(); 213 int ix = componentKeyPath.indexOf('/'); 214 if (ix != -1) { 215 String firstElement = componentKeyPath.substring(0, ix); 216 String remainder = componentKeyPath.substring(ix + 1, componentKeyPath.length()); 217 Object o = getNamedContainers().get(firstElement); 218 if (o != null) { 219 MutablePicoContainer child = (MutablePicoContainer) o; 220 return child.getComponent(remainder); 221 } 222 } 223 return null; 224 } 225 226 public final MutablePicoContainer makeChildContainer() { 227 return makeChildContainer("containers" + namedChildContainers.size()); 228 } 229 230 /** 231 * Makes a child container with the same basic characteristics of 232 * <tt>this</tt> object (ComponentFactory, PicoContainer type, Behavior, 233 * etc) 234 * 235 * @param name the name of the child container 236 * @return The child MutablePicoContainer 237 */ 238 public ClassLoadingPicoContainer makeChildContainer(String name) { 239 DefaultClassLoadingPicoContainer child = createChildContainer(); 240 MutablePicoContainer parentDelegate = getDelegate(); 241 parentDelegate.removeChildContainer(child.getDelegate()); 242 parentDelegate.addChildContainer(child); 243 namedChildContainers.put(name, child); 244 return child; 245 } 246 247 public boolean removeChildContainer(PicoContainer child) { 248 boolean result = getDelegate().removeChildContainer(child); 249 Iterator<Map.Entry<String, PicoContainer>> children = namedChildContainers.entrySet().iterator(); 250 while (children.hasNext()) { 251 Map.Entry<String, PicoContainer> e = children.next(); 252 PicoContainer pc = e.getValue(); 253 if (pc == child) { 254 children.remove(); 255 } 256 } 257 return result; 258 } 259 260 protected final Map<String, PicoContainer> getNamedContainers() { 261 return namedChildContainers; 262 } 263 264 public ClassPathElement addClassLoaderURL(URL url) { 265 if (componentClassLoaderLocked) { 266 throw new IllegalStateException("ClassLoader URLs cannot be added once this instance is locked"); 267 } 268 269 ClassPathElement classPathElement = new ClassPathElement(url); 270 classPathElements.add(classPathElement); 271 return classPathElement; 272 } 273 274 public MutablePicoContainer addComponent(Object implOrInstance) { 275 if (implOrInstance instanceof ClassName) { 276 super.addComponent(loadClass(implOrInstance.toString())); 277 } else { 278 super.addComponent(implOrInstance); 279 } 280 return this; 281 } 282 283 public MutablePicoContainer addComponent(Object key, Object componentImplementationOrInstance, 284 Parameter... parameters) { 285 super.addComponent(classNameToClassIfApplicable(key), 286 classNameToClassIfApplicable(componentImplementationOrInstance), parameters); 287 return this; 288 } 289 290 private Object classNameToClassIfApplicable(Object key) { 291 if (key instanceof ClassName) { 292 key = loadClass(key.toString()); 293 } 294 return key; 295 } 296 297 public MutablePicoContainer addAdapter(ComponentAdapter<?> componentAdapter) throws PicoCompositionException { 298 super.addAdapter(componentAdapter); 299 return this; 300 } 301 302 public ClassLoader getComponentClassLoader() { 303 if (componentClassLoader == null) { 304 componentClassLoaderLocked = true; 305 componentClassLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { 306 public ClassLoader run() { 307 return new CustomPermissionsURLClassLoader(getURLs(classPathElements), makePermissions(), 308 parentClassLoader); 309 } 310 }); 311 } 312 return componentClassLoader; 313 } 314 315 public MutablePicoContainer addChildContainer(PicoContainer child) { 316 getDelegate().addChildContainer(child); 317 namedChildContainers.put("containers" + namedChildContainers.size(), child); 318 return this; 319 } 320 321 public ClassLoadingPicoContainer addChildContainer(String name, PicoContainer child) { 322 323 super.addChildContainer(child); 324 325 namedChildContainers.put(name, child); 326 return this; 327 } 328 329 private Class<?> loadClass(final String className) { 330 ClassLoader classLoader = getComponentClassLoader(); 331 // this is deliberately not a doPrivileged operation. 332 String cn = getClassName(className); 333 try { 334 return classLoader.loadClass(cn); 335 } catch (ClassNotFoundException e) { 336 throw new PicoClassNotFoundException(cn, e); 337 } 338 } 339 340 private Map<URL, Permissions> makePermissions() { 341 Map<URL, Permissions> permissionsMap = new HashMap<URL, Permissions>(); 342 for (ClassPathElement cpe : classPathElements) { 343 Permissions permissionCollection = cpe.getPermissionCollection(); 344 permissionsMap.put(cpe.getUrl(), permissionCollection); 345 } 346 return permissionsMap; 347 } 348 349 private URL[] getURLs(List<ClassPathElement> classPathElemelements) { 350 final URL[] urls = new URL[classPathElemelements.size()]; 351 for (int i = 0; i < urls.length; i++) { 352 urls[i] = (classPathElemelements.get(i)).getUrl(); 353 } 354 return urls; 355 } 356 357 private static String getClassName(String primitiveOrClass) { 358 String fromMap = primitiveNameToBoxedName.get(primitiveOrClass); 359 return fromMap != null ? fromMap : primitiveOrClass; 360 } 361 362 public ComponentAdapter<?> getComponentAdapter(Object componentKey) { 363 Object componentKey2 = componentKey; 364 if (componentKey instanceof ClassName) { 365 componentKey2 = loadClass(componentKey.toString()); 366 } 367 return super.getComponentAdapter(componentKey2); 368 } 369 370 public MutablePicoContainer change(Properties... properties) { 371 super.change(properties); 372 return this; 373 } 374 375 public MutablePicoContainer as(Properties... properties) { 376 return new AsPropertiesPicoContainer(properties); 377 } 378 379 private class AsPropertiesPicoContainer implements ClassLoadingPicoContainer { 380 private MutablePicoContainer delegate; 381 382 public AsPropertiesPicoContainer(Properties... props) { 383 delegate = DefaultClassLoadingPicoContainer.this.getDelegate().as(props); 384 } 385 386 public ClassPathElement addClassLoaderURL(URL url) { 387 return DefaultClassLoadingPicoContainer.this.addClassLoaderURL(url); 388 } 389 390 public ClassLoader getComponentClassLoader() { 391 return DefaultClassLoadingPicoContainer.this.getComponentClassLoader(); 392 } 393 394 public ClassLoadingPicoContainer makeChildContainer(String name) { 395 return DefaultClassLoadingPicoContainer.this.makeChildContainer(name); 396 } 397 398 public ClassLoadingPicoContainer addChildContainer(String name, PicoContainer child) { 399 return (ClassLoadingPicoContainer) DefaultClassLoadingPicoContainer.this.addChildContainer(child); 400 } 401 402 public MutablePicoContainer addComponent(Object componentKey, Object componentImplementationOrInstance, 403 Parameter... parameters) { 404 delegate.addComponent(classNameToClassIfApplicable(componentKey), 405 classNameToClassIfApplicable(componentImplementationOrInstance), parameters); 406 return DefaultClassLoadingPicoContainer.this; 407 } 408 409 public MutablePicoContainer addComponent(Object implOrInstance) { 410 delegate.addComponent(classNameToClassIfApplicable(implOrInstance)); 411 return DefaultClassLoadingPicoContainer.this; 412 } 413 414 public MutablePicoContainer addConfig(String name, Object val) { 415 delegate.addConfig(name, val); 416 return DefaultClassLoadingPicoContainer.this; 417 } 418 419 public MutablePicoContainer addAdapter(ComponentAdapter<?> componentAdapter) { 420 delegate.addAdapter(componentAdapter); 421 return DefaultClassLoadingPicoContainer.this; 422 } 423 424 public ComponentAdapter removeComponent(Object componentKey) { 425 return delegate.removeComponent(componentKey); 426 } 427 428 public ComponentAdapter removeComponentByInstance(Object componentInstance) { 429 return delegate.removeComponentByInstance(componentInstance); 430 } 431 432 public MutablePicoContainer makeChildContainer() { 433 return DefaultClassLoadingPicoContainer.this.makeChildContainer(); 434 } 435 436 public MutablePicoContainer addChildContainer(PicoContainer child) { 437 return DefaultClassLoadingPicoContainer.this.addChildContainer(child); 438 } 439 440 public boolean removeChildContainer(PicoContainer child) { 441 return DefaultClassLoadingPicoContainer.this.removeChildContainer(child); 442 } 443 444 public MutablePicoContainer change(Properties... properties) { 445 return DefaultClassLoadingPicoContainer.this.change(properties); 446 } 447 448 public MutablePicoContainer as(Properties... properties) { 449 return new AsPropertiesPicoContainer(properties); 450 } 451 452 public Object getComponent(Object componentKeyOrType) { 453 return DefaultClassLoadingPicoContainer.this.getComponent(componentKeyOrType); 454 } 455 456 public Object getComponent(Object componentKeyOrType, Type into) { 457 return DefaultClassLoadingPicoContainer.this.getComponent(componentKeyOrType, into); 458 } 459 460 public <T> T getComponent(Class<T> componentType) { 461 return DefaultClassLoadingPicoContainer.this.getComponent(componentType); 462 } 463 464 public <T> T getComponent(Class<T> componentType, Class<? extends Annotation> binding) { 465 return DefaultClassLoadingPicoContainer.this.getComponent(componentType, binding); 466 } 467 468 public List<Object> getComponents() { 469 return DefaultClassLoadingPicoContainer.this.getComponents(); 470 } 471 472 public PicoContainer getParent() { 473 return DefaultClassLoadingPicoContainer.this.getParent(); 474 } 475 476 public ComponentAdapter<?> getComponentAdapter(Object componentKey) { 477 return DefaultClassLoadingPicoContainer.this.getComponentAdapter(componentKey); 478 } 479 480 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, NameBinding componentNameBinding) { 481 return DefaultClassLoadingPicoContainer.this.getComponentAdapter(componentType, componentNameBinding); 482 } 483 484 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, Class<? extends Annotation> binding) { 485 return DefaultClassLoadingPicoContainer.this.getComponentAdapter(componentType, binding); 486 } 487 488 public Collection<ComponentAdapter<?>> getComponentAdapters() { 489 return DefaultClassLoadingPicoContainer.this.getComponentAdapters(); 490 } 491 492 public <T> List<ComponentAdapter<T>> getComponentAdapters(Class<T> componentType) { 493 return DefaultClassLoadingPicoContainer.this.getComponentAdapters(componentType); 494 } 495 496 public <T> List<ComponentAdapter<T>> getComponentAdapters(Class<T> componentType, 497 Class<? extends Annotation> binding) { 498 return DefaultClassLoadingPicoContainer.this.getComponentAdapters(componentType, binding); 499 } 500 501 public <T> List<T> getComponents(Class<T> componentType) { 502 return DefaultClassLoadingPicoContainer.this.getComponents(componentType); 503 } 504 505 public void accept(PicoVisitor visitor) { 506 DefaultClassLoadingPicoContainer.this.accept(visitor); 507 } 508 509 public void start() { 510 511 } 512 513 public void stop() { 514 515 } 516 517 public void dispose() { 518 519 } 520 } 521 522 }