001/***************************************************************************** 002 * Copyright (C) PicoContainer 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 * 009 *****************************************************************************/ 010package org.picocontainer; 011 012import org.picocontainer.adapters.AbstractAdapter; 013import org.picocontainer.adapters.InstanceAdapter; 014import org.picocontainer.behaviors.AbstractBehaviorFactory; 015import org.picocontainer.behaviors.AdaptingBehavior; 016import org.picocontainer.behaviors.Cached; 017import org.picocontainer.behaviors.Caching; 018import org.picocontainer.behaviors.HiddenImplementation; 019import org.picocontainer.containers.AbstractDelegatingMutablePicoContainer; 020import org.picocontainer.containers.AbstractDelegatingPicoContainer; 021import org.picocontainer.containers.EmptyPicoContainer; 022import org.picocontainer.containers.ImmutablePicoContainer; 023import org.picocontainer.converters.BuiltInConverters; 024import org.picocontainer.converters.ConvertsNothing; 025import org.picocontainer.injectors.AbstractInjector; 026import org.picocontainer.injectors.AdaptingInjection; 027import org.picocontainer.injectors.FactoryInjector; 028import org.picocontainer.lifecycle.DefaultLifecycleState; 029import org.picocontainer.lifecycle.LifecycleState; 030import org.picocontainer.lifecycle.StartableLifecycleStrategy; 031import org.picocontainer.monitors.NullComponentMonitor; 032import org.picocontainer.parameters.DefaultConstructorParameter; 033 034import java.io.Serializable; 035import java.lang.annotation.Annotation; 036import java.lang.ref.WeakReference; 037import java.lang.reflect.Type; 038import java.util.ArrayList; 039import java.util.Collection; 040import java.util.Collections; 041import java.util.Enumeration; 042import java.util.HashMap; 043import java.util.HashSet; 044import java.util.LinkedHashSet; 045import java.util.List; 046import java.util.Map; 047import java.util.Properties; 048import java.util.Set; 049 050import static org.picocontainer.parameters.BasicComponentParameter.findInjectorOrInstanceAdapter; 051import static org.picocontainer.parameters.BasicComponentParameter.makeFoundAmbiguousStrings; 052 053/** 054 * <p/> 055 * The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation. 056 * Constructing a container c with a parent p container will cause c to look up components 057 * in p if they cannot be found inside c itself. 058 * </p> 059 * <p/> 060 * Using {@link Class} objects as keys to the various registerXXX() methods makes 061 * a subtle semantic difference: 062 * </p> 063 * <p/> 064 * If there are more than one registered components of the same type and one of them are 065 * registered with a {@link java.lang.Class} key of the corresponding type, this addComponent 066 * will take precedence over other components during type resolution. 067 * </p> 068 * <p/> 069 * Another place where keys that are classes make a subtle difference is in 070 * {@link HiddenImplementation}. 071 * </p> 072 * <p/> 073 * This implementation of {@link MutablePicoContainer} also supports 074 * {@link ComponentMonitorStrategy}. 075 * </p> 076 * 077 * @author Paul Hammant 078 * @author Aslak Hellesøy 079 * @author Jon Tirsén 080 * @author Thomas Heller 081 * @author Mauro Talevi 082 */ 083@SuppressWarnings("serial") 084public class DefaultPicoContainer implements MutablePicoContainer, Converting, ComponentMonitorStrategy, Serializable { 085 086 private String name; 087 088 /** 089 * Component factory instance. 090 */ 091 protected final ComponentFactory componentFactory; 092 093 /** 094 * Parent picocontainer 095 */ 096 private PicoContainer parent; 097 098 /** 099 * All picocontainer children. 100 */ 101 private final Set<PicoContainer> children = new HashSet<PicoContainer>(); 102 103 /** 104 * Current state of the container. 105 */ 106 private LifecycleState lifecycleState = new DefaultLifecycleState(); 107 108 /** 109 * Keeps track of child containers started status. 110 */ 111 private final Set<WeakReference<PicoContainer>> childrenStarted = new HashSet<WeakReference<PicoContainer>>(); 112 113 /** 114 * Lifecycle strategy instance. 115 */ 116 protected final LifecycleStrategy lifecycleStrategy; 117 118 /** 119 * Properties set at the container level, that will affect subsequent components added. 120 */ 121 private final Properties containerProperties = new Properties(); 122 123 /** 124 * Component monitor instance. Receives event callbacks. 125 */ 126 protected ComponentMonitor componentMonitor; 127 128 /** 129 * Map used for looking up component adapters by their key. 130 */ 131 private final Map<Object, ComponentAdapter<?>> componentKeyToAdapterCache = new HashMap<Object, ComponentAdapter<?> >(); 132 133 134 private final Set<ComponentAdapter<?>> componentAdapters = new LinkedHashSet<ComponentAdapter<?>>(); 135 136 137 protected final List<ComponentAdapter<?>> orderedComponentAdapters = new ArrayList<ComponentAdapter<?>>(); 138 139 140 private transient IntoThreadLocal intoThreadLocal; 141 private Converters converters; 142 143 144 /** 145 * Creates a new container with a custom ComponentFactory and a parent container. 146 * <p/> 147 * <em> 148 * Important note about caching: If you intend the components to be cached, you should pass 149 * in a factory that creates {@link Cached} instances, such as for example 150 * {@link Caching}. Caching can delegate to 151 * other ComponentAdapterFactories. 152 * </em> 153 * 154 * @param componentFactory the factory to use for creation of ComponentAdapters. 155 * @param parent the parent container (used for component dependency lookups). 156 */ 157 public DefaultPicoContainer(final ComponentFactory componentFactory, final PicoContainer parent) { 158 this(componentFactory, new StartableLifecycleStrategy(new NullComponentMonitor()), parent, new NullComponentMonitor()); 159 } 160 161 /** 162 * Creates a new container with a custom ComponentFactory, LifecycleStrategy for instance registration, 163 * and a parent container. 164 * <p/> 165 * <em> 166 * Important note about caching: If you intend the components to be cached, you should pass 167 * in a factory that creates {@link Cached} instances, such as for example 168 * {@link Caching}. Caching can delegate to 169 * other ComponentAdapterFactories. 170 * </em> 171 * 172 * @param componentFactory the factory to use for creation of ComponentAdapters. 173 * @param lifecycleStrategy 174 * the lifecycle strategy chosen for registered 175 * instance (not implementations!) 176 * @param parent the parent container (used for component dependency lookups). 177 */ 178 public DefaultPicoContainer(final ComponentFactory componentFactory, 179 final LifecycleStrategy lifecycleStrategy, 180 final PicoContainer parent) { 181 this(componentFactory, lifecycleStrategy, parent, new NullComponentMonitor() ); 182 } 183 184 public DefaultPicoContainer(final ComponentFactory componentFactory, 185 final LifecycleStrategy lifecycleStrategy, 186 final PicoContainer parent, final ComponentMonitor componentMonitor) { 187 if (componentFactory == null) { 188 throw new NullPointerException("componentFactory"); 189 } 190 if (lifecycleStrategy == null) { 191 throw new NullPointerException("lifecycleStrategy"); 192 } 193 this.componentFactory = componentFactory; 194 this.lifecycleStrategy = lifecycleStrategy; 195 this.parent = parent; 196 if (parent != null && !(parent instanceof EmptyPicoContainer)) { 197 this.parent = new ImmutablePicoContainer(parent); 198 } 199 this.componentMonitor = componentMonitor; 200 } 201 202 /** 203 * Creates a new container with the AdaptingInjection using a 204 * custom ComponentMonitor 205 * 206 * @param monitor the ComponentMonitor to use 207 * @param parent the parent container (used for component dependency lookups). 208 */ 209 public DefaultPicoContainer(final ComponentMonitor monitor, final PicoContainer parent) { 210 this(new AdaptingBehavior(), new StartableLifecycleStrategy(monitor), parent, monitor); 211 } 212 213 /** 214 * Creates a new container with the AdaptingInjection using a 215 * custom ComponentMonitor and lifecycle strategy 216 * 217 * @param monitor the ComponentMonitor to use 218 * @param lifecycleStrategy the lifecycle strategy to use. 219 * @param parent the parent container (used for component dependency lookups). 220 */ 221 public DefaultPicoContainer(final ComponentMonitor monitor, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { 222 this(new AdaptingBehavior(), lifecycleStrategy, parent, monitor); 223 } 224 225 /** 226 * Creates a new container with the AdaptingInjection using a 227 * custom lifecycle strategy 228 * 229 * @param lifecycleStrategy the lifecycle strategy to use. 230 * @param parent the parent container (used for component dependency lookups). 231 */ 232 public DefaultPicoContainer(final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { 233 this(new NullComponentMonitor(), lifecycleStrategy, parent); 234 } 235 236 237 /** 238 * Creates a new container with a custom ComponentFactory and no parent container. 239 * 240 * @param componentFactory the ComponentFactory to use. 241 */ 242 public DefaultPicoContainer(final ComponentFactory componentFactory) { 243 this(componentFactory, null); 244 } 245 246 /** 247 * Creates a new container with the AdaptingInjection using a 248 * custom ComponentMonitor 249 * 250 * @param monitor the ComponentMonitor to use 251 */ 252 public DefaultPicoContainer(final ComponentMonitor monitor) { 253 this(monitor, new StartableLifecycleStrategy(monitor), null); 254 } 255 256 /** 257 * Creates a new container with a (caching) {@link AdaptingInjection} 258 * and a parent container. 259 * 260 * @param parent the parent container (used for component dependency lookups). 261 */ 262 public DefaultPicoContainer(final PicoContainer parent) { 263 this(new AdaptingBehavior(), parent); 264 } 265 266 /** Creates a new container with a {@link AdaptingBehavior} and no parent container. */ 267 public DefaultPicoContainer() { 268 this(new AdaptingBehavior(), null); 269 } 270 271 /** {@inheritDoc} **/ 272 public Collection<ComponentAdapter<?>> getComponentAdapters() { 273 return Collections.unmodifiableSet(getModifiableComponentAdapterList()); 274 } 275 276 277 /** {@inheritDoc} **/ 278 public final ComponentAdapter<?> getComponentAdapter(final Object componentKey) { 279 ComponentAdapter<?> adapter = getComponentKeyToAdapterCache().get(componentKey); 280 if (adapter == null && parent != null) { 281 adapter = getParent().getComponentAdapter(componentKey); 282 if (adapter != null) { 283 adapter = new KnowsContainerAdapter(adapter, getParent()); 284 } 285 } 286 if (adapter == null) { 287 Object inst = componentMonitor.noComponentFound(this, componentKey); 288 if (inst != null) { 289 adapter = new LateInstance(componentKey, inst); 290 } 291 } 292 return adapter; 293 } 294 295 public static class LateInstance extends AbstractAdapter { 296 private final Object instance; 297 private LateInstance(Object componentKey, Object instance) { 298 super(componentKey, instance.getClass()); 299 this.instance = instance; 300 } 301 302 public Object getComponentInstance() { 303 return instance; 304 } 305 306 public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException { 307 return instance; 308 } 309 310 public void verify(PicoContainer container) throws PicoCompositionException { 311 } 312 313 public String getDescriptor() { 314 return "LateInstance"; 315 } 316 } 317 318 public static class KnowsContainerAdapter<T> implements ComponentAdapter<T> { 319 private final ComponentAdapter<T> ca; 320 private final PicoContainer ctr; 321 322 public KnowsContainerAdapter(ComponentAdapter<T> ca, PicoContainer ctr) { 323 this.ca = ca; 324 this.ctr = ctr; 325 } 326 327 public T getComponentInstance(Type into) throws PicoCompositionException { 328 return getComponentInstance(ctr, into); 329 } 330 331 public Object getComponentKey() { 332 return ca.getComponentKey(); 333 } 334 335 public Class<? extends T> getComponentImplementation() { 336 return ca.getComponentImplementation(); 337 } 338 339 public T getComponentInstance(PicoContainer container) throws PicoCompositionException { 340 return ca.getComponentInstance(container); 341 } 342 343 public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException { 344 return ca.getComponentInstance(container, into); 345 } 346 347 public void verify(PicoContainer container) throws PicoCompositionException { 348 ca.verify(container); 349 } 350 351 public void accept(PicoVisitor visitor) { 352 ca.accept(visitor); 353 } 354 355 public ComponentAdapter getDelegate() { 356 return ca.getDelegate(); 357 } 358 359 public <U extends ComponentAdapter> U findAdapterOfType(Class<U> adapterType) { 360 return ca.findAdapterOfType(adapterType); 361 } 362 363 public String getDescriptor() { 364 return null; 365 } 366 } 367 368 /** {@inheritDoc} **/ 369 public <T> ComponentAdapter<T> getComponentAdapter(final Class<T> componentType, final NameBinding componentNameBinding) { 370 return getComponentAdapter(componentType, componentNameBinding, null); 371 } 372 373 /** {@inheritDoc} **/ 374 private <T> ComponentAdapter<T> getComponentAdapter(final Class<T> componentType, final NameBinding componentNameBinding, final Class<? extends Annotation> binding) { 375 // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115 376 ComponentAdapter<?> adapterByKey = getComponentAdapter(componentType); 377 if (adapterByKey != null) { 378 return typeComponentAdapter(adapterByKey); 379 } 380 381 List<ComponentAdapter<T>> found = binding == null ? getComponentAdapters(componentType) : getComponentAdapters(componentType, binding); 382 383 if (found.size() == 1) { 384 return found.get(0); 385 } else if (found.isEmpty()) { 386 if (parent != null) { 387 return getParent().getComponentAdapter(componentType, componentNameBinding); 388 } else { 389 return null; 390 } 391 } else { 392 if (componentNameBinding != null) { 393 String parameterName = componentNameBinding.getName(); 394 if (parameterName != null) { 395 ComponentAdapter<?> ca = getComponentAdapter(parameterName); 396 if (ca != null && componentType.isAssignableFrom(ca.getComponentImplementation())) { 397 return typeComponentAdapter(ca); 398 } 399 } 400 } 401 String[] foundStrings = makeFoundAmbiguousStrings(found); 402 throw new AbstractInjector.AmbiguousComponentResolutionException(componentType, foundStrings); 403 } 404 } 405 406 /** {@inheritDoc} **/ 407 public <T> ComponentAdapter<T> getComponentAdapter(final Class<T> componentType, final Class<? extends Annotation> binding) { 408 // 1 409 return getComponentAdapter(componentType, null, binding); 410 } 411 412 /** {@inheritDoc} **/ 413 public <T> List<ComponentAdapter<T>> getComponentAdapters(final Class<T> componentType) { 414 return getComponentAdapters(componentType, null); 415 } 416 417 /** {@inheritDoc} **/ 418 public <T> List<ComponentAdapter<T>> getComponentAdapters(final Class<T> componentType, final Class<? extends Annotation> binding) { 419 if (componentType == null) { 420 return Collections.emptyList(); 421 } 422 List<ComponentAdapter<T>> found = new ArrayList<ComponentAdapter<T>>(); 423 for (ComponentAdapter<?> componentAdapter : getComponentAdapters()) { 424 Object k = componentAdapter.getComponentKey(); 425 426 if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation()) && 427 (!(k instanceof BindKey) || (k instanceof BindKey && (((BindKey<?>)k).getAnnotation() == null || binding == null || 428 ((BindKey<?>)k).getAnnotation() == binding)))) { 429 found.add((ComponentAdapter<T>)typeComponentAdapter(componentAdapter)); 430 } 431 } 432 return found; 433 } 434 435 protected MutablePicoContainer addAdapterInternal(ComponentAdapter<?> componentAdapter) { 436 Object componentKey = componentAdapter.getComponentKey(); 437 if (getComponentKeyToAdapterCache().containsKey(componentKey)) { 438 throw new PicoCompositionException("Duplicate Keys not allowed. Duplicate for '" + componentKey + "'"); 439 } 440 getModifiableComponentAdapterList().add(componentAdapter); 441 getComponentKeyToAdapterCache().put(componentKey, componentAdapter); 442 return this; 443 } 444 445 /** 446 * {@inheritDoc} 447 * This method can be used to override the ComponentAdapter created by the {@link ComponentFactory} 448 * passed to the constructor of this container. 449 */ 450 public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter) { 451 return addAdapter(componentAdapter, this.containerProperties); 452 } 453 454 /** {@inheritDoc} **/ 455 public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter, final Properties properties) { 456 Properties tmpProperties = (Properties)properties.clone(); 457 AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.USE_NAMES); 458 if (AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.NONE) == false && componentFactory instanceof BehaviorFactory) { 459 MutablePicoContainer container = addAdapterInternal(((BehaviorFactory)componentFactory).addComponentAdapter( 460 componentMonitor, 461 lifecycleStrategy, 462 tmpProperties, 463 componentAdapter)); 464 throwIfPropertiesLeft(tmpProperties); 465 return container; 466 } else { 467 return addAdapterInternal(componentAdapter); 468 } 469 470 } 471 472 473 /** {@inheritDoc} **/ 474 public <T> ComponentAdapter<T> removeComponent(final Object componentKey) { 475 lifecycleState.removingComponent(); 476 477 ComponentAdapter<T> adapter = (ComponentAdapter<T>) getComponentKeyToAdapterCache().remove(componentKey); 478 getModifiableComponentAdapterList().remove(adapter); 479 getOrderedComponentAdapters().remove(adapter); 480 return adapter; 481 } 482 483 /** 484 * {@inheritDoc} 485 * The returned ComponentAdapter will be an {@link org.picocontainer.adapters.InstanceAdapter}. 486 */ 487 public MutablePicoContainer addComponent(final Object implOrInstance) { 488 return addComponent(implOrInstance, this.containerProperties); 489 } 490 491 private MutablePicoContainer addComponent(final Object implOrInstance, final Properties props) { 492 Class<?> clazz; 493 if (implOrInstance instanceof String) { 494 return addComponent(implOrInstance, implOrInstance); 495 } 496 if (implOrInstance instanceof Class) { 497 clazz = (Class<?>)implOrInstance; 498 } else { 499 clazz = implOrInstance.getClass(); 500 } 501 return addComponent(clazz, implOrInstance, props); 502 } 503 504 505 public MutablePicoContainer addConfig(final String name, final Object val) { 506 return addAdapterInternal(new InstanceAdapter<Object>(name, val, lifecycleStrategy, componentMonitor)); 507 } 508 509 510 /** 511 * {@inheritDoc} 512 * The returned ComponentAdapter will be instantiated by the {@link ComponentFactory} 513 * passed to the container's constructor. 514 */ 515 public MutablePicoContainer addComponent(final Object componentKey, 516 final Object componentImplementationOrInstance, 517 final Parameter... parameters) { 518 return this.addComponent(componentKey, componentImplementationOrInstance, this.containerProperties, parameters); 519 } 520 521 private MutablePicoContainer addComponent(final Object componentKey, 522 final Object componentImplementationOrInstance, 523 final Properties properties, 524 Parameter... parameters) { 525 if (parameters != null && parameters.length == 0) { 526 parameters = null; // backwards compatibility! solve this better later - Paul 527 } 528 529 //New replacement for Parameter.ZERO. 530 if (parameters != null && parameters.length == 1 && DefaultConstructorParameter.INSTANCE.equals(parameters[0])) { 531 parameters = new Parameter[0]; 532 } 533 534 if (componentImplementationOrInstance instanceof Class) { 535 Properties tmpProperties = (Properties) properties.clone(); 536 ComponentAdapter<?> adapter = componentFactory.createComponentAdapter(componentMonitor, 537 lifecycleStrategy, 538 tmpProperties, 539 componentKey, 540 (Class<?>)componentImplementationOrInstance, 541 parameters); 542 AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.USE_NAMES); 543 throwIfPropertiesLeft(tmpProperties); 544 if (lifecycleState.isStarted()) { 545 addAdapterIfStartable(adapter); 546 potentiallyStartAdapter(adapter); 547 } 548 return addAdapterInternal(adapter); 549 } else { 550 ComponentAdapter<?> adapter = 551 new InstanceAdapter<Object>(componentKey, componentImplementationOrInstance, lifecycleStrategy, componentMonitor); 552 if (lifecycleState.isStarted()) { 553 addAdapterIfStartable(adapter); 554 potentiallyStartAdapter(adapter); 555 } 556 return addAdapter(adapter, properties); 557 } 558 } 559 560 private void throwIfPropertiesLeft(final Properties tmpProperties) { 561 if(tmpProperties.size() > 0) { 562 throw new PicoCompositionException("Unprocessed Characteristics:" + tmpProperties +", please refer to http://picocontainer.org/unprocessed-properties-help.html"); 563 } 564 } 565 566 private synchronized void addOrderedComponentAdapter(final ComponentAdapter<?> componentAdapter) { 567 if (!getOrderedComponentAdapters().contains(componentAdapter)) { 568 getOrderedComponentAdapters().add(componentAdapter); 569 } 570 } 571 572 public List<Object> getComponents() throws PicoException { 573 return getComponents(Object.class); 574 } 575 576 public <T> List<T> getComponents(final Class<T> componentType) { 577 if (componentType == null) { 578 return Collections.emptyList(); 579 } 580 581 Map<ComponentAdapter<T>, T> adapterToInstanceMap = new HashMap<ComponentAdapter<T>, T>(); 582 List<T> result = new ArrayList<T>(); 583 synchronized(this) { 584 for (ComponentAdapter<?> componentAdapter : getModifiableComponentAdapterList()) { 585 if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) { 586 ComponentAdapter<T> typedComponentAdapter = typeComponentAdapter(componentAdapter); 587 T componentInstance = getLocalInstance(typedComponentAdapter); 588 589 adapterToInstanceMap.put(typedComponentAdapter, componentInstance); 590 } 591 } 592 593 for (ComponentAdapter<?> componentAdapter : getOrderedComponentAdapters()) { 594 final T componentInstance = adapterToInstanceMap.get(componentAdapter); 595 if (componentInstance != null) { 596 // may be null in the case of the "implicit" addAdapter 597 // representing "this". 598 result.add(componentInstance); 599 } 600 } 601 } 602 return result; 603 } 604 605 private <T> T getLocalInstance(final ComponentAdapter<T> typedComponentAdapter) { 606 T componentInstance = typedComponentAdapter.getComponentInstance(this, ComponentAdapter.NOTHING.class); 607 608 // This is to ensure all are added. (Indirect dependencies will be added 609 // from InstantiatingComponentAdapter). 610 addOrderedComponentAdapter(typedComponentAdapter); 611 612 return componentInstance; 613 } 614 615 @SuppressWarnings({ "unchecked" }) 616 private static <T> ComponentAdapter<T> typeComponentAdapter(final ComponentAdapter<?> componentAdapter) { 617 return (ComponentAdapter<T>)componentAdapter; 618 } 619 620 public Object getComponent(final Object componentKeyOrType) { 621 return getComponent(componentKeyOrType, null); 622 } 623 624 public Object getComponent(final Object componentKeyOrType, Type into) { 625 synchronized (this) { 626 if (intoThreadLocal == null) { 627 intoThreadLocal = new IntoThreadLocal(); 628 } 629 } 630 intoThreadLocal.set(into); 631 try { 632 return getComponent(componentKeyOrType, (Class<? extends Annotation>) null); 633 } finally { 634 intoThreadLocal.set(null); 635 } 636 } 637 638 public Object getComponent(final Object componentKeyOrType, final Class<? extends Annotation> annotation) { 639 ComponentAdapter<?> componentAdapter = null; 640 Object component; 641 try { 642 if (annotation != null) { 643 componentAdapter = getComponentAdapter((Class<?>)componentKeyOrType, annotation); 644 component = componentAdapter == null ? null : getInstance(componentAdapter, null); 645 } else if (componentKeyOrType instanceof Class) { 646 componentAdapter = getComponentAdapter((Class<?>)componentKeyOrType, (NameBinding) null); 647 component = componentAdapter == null ? null : getInstance(componentAdapter, (Class<?>)componentKeyOrType); 648 } else { 649 componentAdapter = getComponentAdapter(componentKeyOrType); 650 component = componentAdapter == null ? null : getInstance(componentAdapter, null); 651 } 652 } catch (AbstractInjector.AmbiguousComponentResolutionException e) { 653 if (componentAdapter != null) { 654 e.setComponent(findInjectorOrInstanceAdapter(componentAdapter).toString()); 655 } 656 throw e; 657 } 658 return decorateComponent(component, componentAdapter); 659 } 660 661 /** 662 * This is invoked when getComponent(..) is called. It allows extendees to decorate a 663 * component before it is returned to the caller. 664 * @param component the component that will be returned for getComponent(..) 665 * @param componentAdapter the component adapter that made that component 666 * @return the component (the same as that passed in by default) 667 */ 668 protected Object decorateComponent(Object component, ComponentAdapter<?> componentAdapter) { 669 if (componentAdapter instanceof ComponentLifecycle<?> 670 && lifecycleStrategy.isLazy(componentAdapter) // is Lazy 671 && !((ComponentLifecycle<?>) componentAdapter).isStarted()) { 672 ((ComponentLifecycle<?>)componentAdapter).start(this); 673 } 674 return component; 675 } 676 677 public <T> T getComponent(final Class<T> componentType) { 678 Object o = getComponent((Object)componentType, null); 679 return componentType.cast(o); 680 } 681 682 public <T> T getComponent(final Class<T> componentType, final Class<? extends Annotation> binding) { 683 Object o = getComponent((Object)componentType, binding); 684 return componentType.cast(o); 685 } 686 687 688 private Object getInstance(final ComponentAdapter<?> componentAdapter, Class componentKey) { 689 // check whether this is our adapter 690 // we need to check this to ensure up-down dependencies cannot be followed 691 final boolean isLocal = getModifiableComponentAdapterList().contains(componentAdapter); 692 693 if (isLocal || componentAdapter instanceof LateInstance) { 694 Object instance; 695 try { 696 if (componentAdapter instanceof FactoryInjector) { 697 instance = ((FactoryInjector) componentAdapter).getComponentInstance(this, getInto()); 698 } else { 699 instance = componentAdapter.getComponentInstance(this, getInto()); 700 } 701 } catch (AbstractInjector.CyclicDependencyException e) { 702 if (parent != null) { 703 instance = getParent().getComponent(componentAdapter.getComponentKey()); 704 if (instance != null) { 705 return instance; 706 } 707 } 708 throw e; 709 } 710 addOrderedComponentAdapter(componentAdapter); 711 712 return instance; 713 } else if (parent != null) { 714 Object key = componentKey; 715 if (key == null) { 716 key = componentAdapter.getComponentKey(); 717 } 718 return getParent().getComponent(key); 719 } 720 721 return null; 722 } 723 724 private Type getInto() { 725 if (intoThreadLocal == null) { 726 return null; 727 } 728 return intoThreadLocal.get(); 729 } 730 731 732 /** {@inheritDoc} **/ 733 public PicoContainer getParent() { 734 return parent; 735 } 736 737 /** {@inheritDoc} **/ 738 public <T> ComponentAdapter<T> removeComponentByInstance(final T componentInstance) { 739 for (ComponentAdapter<?> componentAdapter : getModifiableComponentAdapterList()) { 740 if (getLocalInstance(componentAdapter).equals(componentInstance)) { 741 return removeComponent(componentAdapter.getComponentKey()); 742 } 743 } 744 return null; 745 } 746 747 /** 748 * Start the components of this PicoContainer and all its logical child containers. 749 * The starting of the child container is only attempted if the parent 750 * container start successfully. The child container for which start is attempted 751 * is tracked so that upon stop, only those need to be stopped. 752 * The lifecycle operation is delegated to the component adapter, 753 * if it is an instance of {@link Behavior lifecycle manager}. 754 * The actual {@link LifecycleStrategy lifecycle strategy} supported 755 * depends on the concrete implementation of the adapter. 756 * 757 * @see Behavior 758 * @see LifecycleStrategy 759 * @see #makeChildContainer() 760 * @see #addChildContainer(PicoContainer) 761 * @see #removeChildContainer(PicoContainer) 762 */ 763 public synchronized void start() { 764 765 lifecycleState.starting(); 766 767 startAdapters(); 768 childrenStarted.clear(); 769 for (PicoContainer child : children) { 770 childrenStarted.add(new WeakReference<PicoContainer>(child)); 771 if (child instanceof Startable) { 772 ((Startable)child).start(); 773 } 774 } 775 } 776 777 /** 778 * Stop the components of this PicoContainer and all its logical child containers. 779 * The stopping of the child containers is only attempted for those that have been 780 * started, possibly not successfully. 781 * The lifecycle operation is delegated to the component adapter, 782 * if it is an instance of {@link Behavior lifecycle manager}. 783 * The actual {@link LifecycleStrategy lifecycle strategy} supported 784 * depends on the concrete implementation of the adapter. 785 * 786 * @see Behavior 787 * @see LifecycleStrategy 788 * @see #makeChildContainer() 789 * @see #addChildContainer(PicoContainer) 790 * @see #removeChildContainer(PicoContainer) 791 */ 792 public synchronized void stop() { 793 794 lifecycleState.stopping(); 795 796 for (PicoContainer child : children) { 797 if (childStarted(child)) { 798 if (child instanceof Startable) { 799 ((Startable)child).stop(); 800 } 801 } 802 } 803 stopAdapters(); 804 lifecycleState.stopped(); 805 } 806 807 /** 808 * Checks the status of the child container to see if it's been started 809 * to prevent IllegalStateException upon stop 810 * 811 * @param child the child PicoContainer 812 * 813 * @return A boolean, <code>true</code> if the container is started 814 */ 815 private boolean childStarted(final PicoContainer child) { 816 for (WeakReference<PicoContainer> eachChild : childrenStarted) { 817 PicoContainer ref = eachChild.get(); 818 if (ref == null) { 819 continue; 820 } 821 822 if (child.equals(ref)) { 823 return true; 824 } 825 } 826 return false; 827 } 828 829 /** 830 * Dispose the components of this PicoContainer and all its logical child containers. 831 * The lifecycle operation is delegated to the component adapter, 832 * if it is an instance of {@link Behavior lifecycle manager}. 833 * The actual {@link LifecycleStrategy lifecycle strategy} supported 834 * depends on the concrete implementation of the adapter. 835 * 836 * @see Behavior 837 * @see LifecycleStrategy 838 * @see #makeChildContainer() 839 * @see #addChildContainer(PicoContainer) 840 * @see #removeChildContainer(PicoContainer) 841 */ 842 public synchronized void dispose() { 843 if (lifecycleState.isStarted()) { 844 stop(); 845 } 846 847 lifecycleState.disposing(); 848 849 for (PicoContainer child : children) { 850 if (child instanceof MutablePicoContainer) { 851 ((Disposable)child).dispose(); 852 } 853 } 854 disposeAdapters(); 855 856 lifecycleState.disposed(); 857 } 858 859 public synchronized void setLifecycleState(LifecycleState lifecycleState) { 860 this.lifecycleState = lifecycleState; 861 } 862 863 public MutablePicoContainer makeChildContainer() { 864 DefaultPicoContainer pc = new DefaultPicoContainer(componentFactory, lifecycleStrategy, this, componentMonitor); 865 addChildContainer(pc); 866 return pc; 867 } 868 869 /** 870 * Checks for identical references in the child container. It doesn't 871 * traverse an entire hierarchy, namely it simply checks for child containers 872 * that are equal to the current container. 873 * @param child 874 */ 875 private void checkCircularChildDependencies(PicoContainer child) { 876 final String MESSAGE = "Cannot have circular dependency between parent %s and child: %s"; 877 if (child == this) { 878 throw new IllegalArgumentException(String.format(MESSAGE,this,child)); 879 } 880 881 //Todo: Circular Import Dependency on AbstractDelegatingPicoContainer 882 if (child instanceof AbstractDelegatingPicoContainer) { 883 AbstractDelegatingPicoContainer delegateChild = (AbstractDelegatingPicoContainer) child; 884 while(delegateChild != null) { 885 PicoContainer delegateInstance = delegateChild.getDelegate(); 886 if (this == delegateInstance) { 887 throw new IllegalArgumentException(String.format(MESSAGE,this,child)); 888 } 889 if (delegateInstance instanceof AbstractDelegatingPicoContainer) { 890 delegateChild = (AbstractDelegatingPicoContainer) delegateInstance; 891 } else { 892 delegateChild = null; 893 } 894 } 895 } 896 897 } 898 899 public MutablePicoContainer addChildContainer(final PicoContainer child) { 900 checkCircularChildDependencies(child); 901 if (children.add(child)) { 902 // TODO Should only be added if child container has also be started 903 if (lifecycleState.isStarted()) { 904 childrenStarted.add(new WeakReference<PicoContainer>(child)); 905 } 906 } 907 return this; 908 } 909 910 public boolean removeChildContainer(final PicoContainer child) { 911 final boolean result = children.remove(child); 912 WeakReference<PicoContainer> foundRef = null; 913 for (WeakReference<PicoContainer> eachChild : childrenStarted) { 914 PicoContainer ref = eachChild.get(); 915 if (ref.equals(child)) { 916 foundRef = eachChild; 917 break; 918 } 919 } 920 921 if (foundRef != null) { 922 childrenStarted.remove(foundRef); 923 } 924 925 return result; 926 } 927 928 public MutablePicoContainer change(final Properties... properties) { 929 for (Properties c : properties) { 930 Enumeration<String> e = (Enumeration<String>) c.propertyNames(); 931 while (e.hasMoreElements()) { 932 String s = e.nextElement(); 933 containerProperties.setProperty(s,c.getProperty(s)); 934 } 935 } 936 return this; 937 } 938 939 public MutablePicoContainer as(final Properties... properties) { 940 return new AsPropertiesPicoContainer(properties); 941 } 942 943 public void accept(final PicoVisitor visitor) { 944 945 //TODO Pico 3 : change accept signatures to allow abort at any point in the traversal. 946 boolean shouldContinue = visitor.visitContainer(this); 947 if (!shouldContinue) { 948 return; 949 } 950 951 952 componentFactory.accept(visitor); // will cascade through behaviors 953 final List<ComponentAdapter<?>> componentAdapters = new ArrayList<ComponentAdapter<?>>(getComponentAdapters()); 954 for (ComponentAdapter<?> componentAdapter : componentAdapters) { 955 componentAdapter.accept(visitor); 956 } 957 final List<PicoContainer> allChildren = new ArrayList<PicoContainer>(children); 958 for (PicoContainer child : allChildren) { 959 child.accept(visitor); 960 } 961 } 962 963 /** 964 * Changes monitor in the ComponentFactory, the component adapters 965 * and the child containers, if these support a ComponentMonitorStrategy. 966 * {@inheritDoc} 967 */ 968 public void changeMonitor(final ComponentMonitor monitor) { 969 this.componentMonitor = monitor; 970 if (lifecycleStrategy instanceof ComponentMonitorStrategy) { 971 ((ComponentMonitorStrategy)lifecycleStrategy).changeMonitor(monitor); 972 } 973 for (ComponentAdapter<?> adapter : getModifiableComponentAdapterList()) { 974 if (adapter instanceof ComponentMonitorStrategy) { 975 ((ComponentMonitorStrategy)adapter).changeMonitor(monitor); 976 } 977 } 978 for (PicoContainer child : children) { 979 if (child instanceof ComponentMonitorStrategy) { 980 ((ComponentMonitorStrategy)child).changeMonitor(monitor); 981 } 982 } 983 } 984 985 /** 986 * Returns the first current monitor found in the ComponentFactory, the component adapters 987 * and the child containers, if these support a ComponentMonitorStrategy. 988 * {@inheritDoc} 989 * 990 * @throws PicoCompositionException if no component monitor is found in container or its children 991 */ 992 public ComponentMonitor currentMonitor() { 993 return componentMonitor; 994 } 995 996 /** 997 * Loops over all component adapters and invokes 998 * start(PicoContainer) method on the ones which are LifecycleManagers 999 */ 1000 private void startAdapters() { 1001 Collection<ComponentAdapter<?>> adapters = getComponentAdapters(); 1002 for (ComponentAdapter<?> adapter : adapters) { 1003 addAdapterIfStartable(adapter); 1004 } 1005 adapters = getOrderedComponentAdapters(); 1006 // clone the adapters 1007 List<ComponentAdapter<?>> adaptersClone = new ArrayList<ComponentAdapter<?>>(adapters); 1008 for (final ComponentAdapter<?> adapter : adaptersClone) { 1009 potentiallyStartAdapter(adapter); 1010 } 1011 } 1012 1013 protected void potentiallyStartAdapter(ComponentAdapter<?> adapter) { 1014 if (adapter instanceof ComponentLifecycle) { 1015 if (!lifecycleStrategy.isLazy(adapter)) { 1016 ((ComponentLifecycle<?>)adapter).start(this); 1017 } 1018 } 1019 } 1020 1021 private void addAdapterIfStartable(ComponentAdapter<?> adapter) { 1022 if (adapter instanceof ComponentLifecycle) { 1023 ComponentLifecycle<?> componentLifecycle = (ComponentLifecycle<?>)adapter; 1024 if (componentLifecycle.componentHasLifecycle()) { 1025 // create an instance, it will be added to the ordered CA list 1026 instantiateComponentAsIsStartable(adapter); 1027 addOrderedComponentAdapter(adapter); 1028 } 1029 } 1030 } 1031 1032 protected void instantiateComponentAsIsStartable(ComponentAdapter<?> adapter) { 1033 if (!lifecycleStrategy.isLazy(adapter)) { 1034 adapter.getComponentInstance(DefaultPicoContainer.this, ComponentAdapter.NOTHING.class); 1035 } 1036 } 1037 1038 /** 1039 * Loops over started component adapters (in inverse order) and invokes 1040 * stop(PicoContainer) method on the ones which are LifecycleManagers 1041 */ 1042 private void stopAdapters() { 1043 for (int i = getOrderedComponentAdapters().size() - 1; 0 <= i; i--) { 1044 ComponentAdapter<?> adapter = getOrderedComponentAdapters().get(i); 1045 if (adapter instanceof ComponentLifecycle) { 1046 ComponentLifecycle<?> componentLifecycle = (ComponentLifecycle<?>)adapter; 1047 if (componentLifecycle.componentHasLifecycle() && componentLifecycle.isStarted()) { 1048 componentLifecycle.stop(DefaultPicoContainer.this); 1049 } 1050 } 1051 } 1052 } 1053 1054 /** 1055 * Loops over all component adapters (in inverse order) and invokes 1056 * dispose(PicoContainer) method on the ones which are LifecycleManagers 1057 */ 1058 private void disposeAdapters() { 1059 for (int i = getOrderedComponentAdapters().size() - 1; 0 <= i; i--) { 1060 ComponentAdapter<?> adapter = getOrderedComponentAdapters().get(i); 1061 if (adapter instanceof ComponentLifecycle) { 1062 ComponentLifecycle<?> componentLifecycle = (ComponentLifecycle<?>)adapter; 1063 componentLifecycle.dispose(DefaultPicoContainer.this); 1064 } 1065 } 1066 } 1067 1068 1069 1070 /** 1071 * @return the orderedComponentAdapters 1072 */ 1073 protected List<ComponentAdapter<?>> getOrderedComponentAdapters() { 1074 return orderedComponentAdapters; 1075 } 1076 1077 /** 1078 * @return the componentKeyToAdapterCache 1079 */ 1080 protected Map<Object, ComponentAdapter<?>> getComponentKeyToAdapterCache() { 1081 return componentKeyToAdapterCache; 1082 } 1083 1084 /** 1085 * @return the componentAdapters 1086 */ 1087 protected Set<ComponentAdapter<?>> getModifiableComponentAdapterList() { 1088 return componentAdapters; 1089 } 1090 1091 public synchronized void setName(String name) { 1092 this.name = name; 1093 } 1094 1095 @Override 1096 public String toString() { 1097 return String.format("%s:%d<%s", (name != null ? name : super.toString()), this.componentAdapters.size(), (parent != null && !(parent instanceof EmptyPicoContainer)? parent.toString() : "|")); 1098 } 1099 1100 /** 1101 * If this container has a set of converters, then return it. 1102 * If it does not, and the parent (or their parent ..) does, use that 1103 * If they do not, return a NullObject implementation (ConversNothing) 1104 * @return the converters 1105 */ 1106 public synchronized Converters getConverters() { 1107 if (converters == null) { 1108 if (parent == null || (parent instanceof Converting && ((Converting) parent).getConverters() instanceof ConvertsNothing)) { 1109 converters = new BuiltInConverters(); 1110 } else { 1111 return ((Converting) parent).getConverters(); 1112 } 1113 } 1114 return converters; 1115 } 1116 1117 @SuppressWarnings("synthetic-access") 1118 private class AsPropertiesPicoContainer extends AbstractDelegatingMutablePicoContainer { 1119 1120 private final Properties properties; 1121 1122 public AsPropertiesPicoContainer(final Properties... props) { 1123 super(DefaultPicoContainer.this); 1124 properties = (Properties) containerProperties.clone(); 1125 for (Properties c : props) { 1126 Enumeration<?> e = c.propertyNames(); 1127 while (e.hasMoreElements()) { 1128 String s = (String)e.nextElement(); 1129 properties.setProperty(s,c.getProperty(s)); 1130 } 1131 } 1132 } 1133 1134 @Override 1135 @SuppressWarnings("unused") 1136 public MutablePicoContainer as( Properties... props) { 1137 throw new PicoCompositionException("Syntax 'as(FOO).as(BAR)' not allowed, do 'as(FOO, BAR)' instead"); 1138 } 1139 1140 @Override 1141 public MutablePicoContainer makeChildContainer() { 1142 return getDelegate().makeChildContainer(); 1143 } 1144 1145 @Override 1146 public MutablePicoContainer addComponent(final Object componentKey, 1147 final Object componentImplementationOrInstance, 1148 final Parameter... parameters) throws PicoCompositionException { 1149 return DefaultPicoContainer.this.addComponent(componentKey, 1150 componentImplementationOrInstance, 1151 properties, 1152 parameters); 1153 } 1154 1155 @Override 1156 public MutablePicoContainer addComponent(final Object implOrInstance) throws PicoCompositionException { 1157 return DefaultPicoContainer.this.addComponent(implOrInstance, properties); 1158 } 1159 1160 @Override 1161 public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter) throws PicoCompositionException { 1162 return DefaultPicoContainer.this.addAdapter(componentAdapter, properties); 1163 } 1164 1165 /** 1166 * {@inheritDoc} 1167 * @see org.picocontainer.MutablePicoContainer#getLifecycleState() 1168 */ 1169 @Override 1170 public LifecycleState getLifecycleState() { 1171 return DefaultPicoContainer.this.getLifecycleState(); 1172 } 1173 1174 /** 1175 * {@inheritDoc} 1176 * @see org.picocontainer.MutablePicoContainer#getName() 1177 */ 1178 @Override 1179 public String getName() { 1180 return DefaultPicoContainer.this.getName(); 1181 } 1182 } 1183 1184 private static class IntoThreadLocal extends ThreadLocal<Type> implements Serializable { 1185 @Override 1186 protected Type initialValue() { 1187 return ComponentAdapter.NOTHING.class; 1188 } 1189 } 1190 1191 /** 1192 * {@inheritDoc} 1193 * @see org.picocontainer.MutablePicoContainer#getLifecycleState() 1194 */ 1195 public synchronized LifecycleState getLifecycleState() { 1196 return lifecycleState; 1197 } 1198 1199 /** 1200 * {@inheritDoc} 1201 * @see org.picocontainer.MutablePicoContainer#getName() 1202 */ 1203 public synchronized String getName() { 1204 return this.name; 1205 } 1206 1207}