All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.picocontainer.DefaultPicoContainer Maven / Gradle / Ivy

The newest version!
/*****************************************************************************
 * Copyright (C) PicoContainer Organization. All rights reserved.            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *                                                                           *
 * Original code by                                                          *
 *****************************************************************************/
package org.picocontainer;

import org.picocontainer.adapters.AbstractAdapter;
import org.picocontainer.adapters.InstanceAdapter;
import org.picocontainer.behaviors.AbstractBehaviorFactory;
import org.picocontainer.behaviors.AdaptingBehavior;
import org.picocontainer.behaviors.Cached;
import org.picocontainer.behaviors.Caching;
import org.picocontainer.behaviors.HiddenImplementation;
import org.picocontainer.containers.AbstractDelegatingMutablePicoContainer;
import org.picocontainer.containers.AbstractDelegatingPicoContainer;
import org.picocontainer.containers.EmptyPicoContainer;
import org.picocontainer.containers.ImmutablePicoContainer;
import org.picocontainer.converters.BuiltInConverters;
import org.picocontainer.converters.ConvertsNothing;
import org.picocontainer.injectors.AbstractInjector;
import org.picocontainer.injectors.AdaptingInjection;
import org.picocontainer.injectors.FactoryInjector;
import org.picocontainer.lifecycle.DefaultLifecycleState;
import org.picocontainer.lifecycle.LifecycleState;
import org.picocontainer.lifecycle.StartableLifecycleStrategy;
import org.picocontainer.monitors.NullComponentMonitor;
import org.picocontainer.parameters.DefaultConstructorParameter;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import static org.picocontainer.parameters.BasicComponentParameter.findInjectorOrInstanceAdapter;
import static org.picocontainer.parameters.BasicComponentParameter.makeFoundAmbiguousStrings;

/**
 * 

* The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation. * Constructing a container c with a parent p container will cause c to look up components * in p if they cannot be found inside c itself. *

*

* Using {@link Class} objects as keys to the various registerXXX() methods makes * a subtle semantic difference: *

*

* If there are more than one registered components of the same type and one of them are * registered with a {@link java.lang.Class} key of the corresponding type, this addComponent * will take precedence over other components during type resolution. *

*

* Another place where keys that are classes make a subtle difference is in * {@link HiddenImplementation}. *

*

* This implementation of {@link MutablePicoContainer} also supports * {@link ComponentMonitorStrategy}. *

* * @author Paul Hammant * @author Aslak Hellesøy * @author Jon Tirsén * @author Thomas Heller * @author Mauro Talevi */ @SuppressWarnings("serial") public class DefaultPicoContainer implements MutablePicoContainer, Converting, ComponentMonitorStrategy, Serializable { private String name; /** * Component factory instance. */ protected final ComponentFactory componentFactory; /** * Parent picocontainer */ private PicoContainer parent; /** * All picocontainer children. */ private final Set children = new HashSet(); /** * Current state of the container. */ private LifecycleState lifecycleState = new DefaultLifecycleState(); /** * Keeps track of child containers started status. */ private final Set> childrenStarted = new HashSet>(); /** * Lifecycle strategy instance. */ protected final LifecycleStrategy lifecycleStrategy; /** * Properties set at the container level, that will affect subsequent components added. */ private final Properties containerProperties = new Properties(); /** * Component monitor instance. Receives event callbacks. */ protected ComponentMonitor componentMonitor; /** * Map used for looking up component adapters by their key. */ private final Map> componentKeyToAdapterCache = new HashMap >(); private final Set> componentAdapters = new LinkedHashSet>(); protected final List> orderedComponentAdapters = new ArrayList>(); private transient IntoThreadLocal intoThreadLocal; private Converters converters; /** * Creates a new container with a custom ComponentFactory and a parent container. *

* * Important note about caching: If you intend the components to be cached, you should pass * in a factory that creates {@link Cached} instances, such as for example * {@link Caching}. Caching can delegate to * other ComponentAdapterFactories. * * * @param componentFactory the factory to use for creation of ComponentAdapters. * @param parent the parent container (used for component dependency lookups). */ public DefaultPicoContainer(final ComponentFactory componentFactory, final PicoContainer parent) { this(componentFactory, new StartableLifecycleStrategy(new NullComponentMonitor()), parent, new NullComponentMonitor()); } /** * Creates a new container with a custom ComponentFactory, LifecycleStrategy for instance registration, * and a parent container. *

* * Important note about caching: If you intend the components to be cached, you should pass * in a factory that creates {@link Cached} instances, such as for example * {@link Caching}. Caching can delegate to * other ComponentAdapterFactories. * * * @param componentFactory the factory to use for creation of ComponentAdapters. * @param lifecycleStrategy * the lifecycle strategy chosen for registered * instance (not implementations!) * @param parent the parent container (used for component dependency lookups). */ public DefaultPicoContainer(final ComponentFactory componentFactory, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { this(componentFactory, lifecycleStrategy, parent, new NullComponentMonitor() ); } public DefaultPicoContainer(final ComponentFactory componentFactory, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent, final ComponentMonitor componentMonitor) { if (componentFactory == null) { throw new NullPointerException("componentFactory"); } if (lifecycleStrategy == null) { throw new NullPointerException("lifecycleStrategy"); } this.componentFactory = componentFactory; this.lifecycleStrategy = lifecycleStrategy; this.parent = parent; if (parent != null && !(parent instanceof EmptyPicoContainer)) { this.parent = new ImmutablePicoContainer(parent); } this.componentMonitor = componentMonitor; } /** * Creates a new container with the AdaptingInjection using a * custom ComponentMonitor * * @param monitor the ComponentMonitor to use * @param parent the parent container (used for component dependency lookups). */ public DefaultPicoContainer(final ComponentMonitor monitor, final PicoContainer parent) { this(new AdaptingBehavior(), new StartableLifecycleStrategy(monitor), parent, monitor); } /** * Creates a new container with the AdaptingInjection using a * custom ComponentMonitor and lifecycle strategy * * @param monitor the ComponentMonitor to use * @param lifecycleStrategy the lifecycle strategy to use. * @param parent the parent container (used for component dependency lookups). */ public DefaultPicoContainer(final ComponentMonitor monitor, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { this(new AdaptingBehavior(), lifecycleStrategy, parent, monitor); } /** * Creates a new container with the AdaptingInjection using a * custom lifecycle strategy * * @param lifecycleStrategy the lifecycle strategy to use. * @param parent the parent container (used for component dependency lookups). */ public DefaultPicoContainer(final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { this(new NullComponentMonitor(), lifecycleStrategy, parent); } /** * Creates a new container with a custom ComponentFactory and no parent container. * * @param componentFactory the ComponentFactory to use. */ public DefaultPicoContainer(final ComponentFactory componentFactory) { this(componentFactory, null); } /** * Creates a new container with the AdaptingInjection using a * custom ComponentMonitor * * @param monitor the ComponentMonitor to use */ public DefaultPicoContainer(final ComponentMonitor monitor) { this(monitor, new StartableLifecycleStrategy(monitor), null); } /** * Creates a new container with a (caching) {@link AdaptingInjection} * and a parent container. * * @param parent the parent container (used for component dependency lookups). */ public DefaultPicoContainer(final PicoContainer parent) { this(new AdaptingBehavior(), parent); } /** Creates a new container with a {@link AdaptingBehavior} and no parent container. */ public DefaultPicoContainer() { this(new AdaptingBehavior(), null); } /** {@inheritDoc} **/ public Collection> getComponentAdapters() { return Collections.unmodifiableSet(getModifiableComponentAdapterList()); } /** {@inheritDoc} **/ public final ComponentAdapter getComponentAdapter(final Object componentKey) { ComponentAdapter adapter = getComponentKeyToAdapterCache().get(componentKey); if (adapter == null && parent != null) { adapter = getParent().getComponentAdapter(componentKey); if (adapter != null) { adapter = new KnowsContainerAdapter(adapter, getParent()); } } if (adapter == null) { Object inst = componentMonitor.noComponentFound(this, componentKey); if (inst != null) { adapter = new LateInstance(componentKey, inst); } } return adapter; } public static class LateInstance extends AbstractAdapter { private final Object instance; private LateInstance(Object componentKey, Object instance) { super(componentKey, instance.getClass()); this.instance = instance; } public Object getComponentInstance() { return instance; } public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException { return instance; } public void verify(PicoContainer container) throws PicoCompositionException { } public String getDescriptor() { return "LateInstance"; } } public static class KnowsContainerAdapter implements ComponentAdapter { private final ComponentAdapter ca; private final PicoContainer ctr; public KnowsContainerAdapter(ComponentAdapter ca, PicoContainer ctr) { this.ca = ca; this.ctr = ctr; } public T getComponentInstance(Type into) throws PicoCompositionException { return getComponentInstance(ctr, into); } public Object getComponentKey() { return ca.getComponentKey(); } public Class getComponentImplementation() { return ca.getComponentImplementation(); } public T getComponentInstance(PicoContainer container) throws PicoCompositionException { return ca.getComponentInstance(container); } public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException { return ca.getComponentInstance(container, into); } public void verify(PicoContainer container) throws PicoCompositionException { ca.verify(container); } public void accept(PicoVisitor visitor) { ca.accept(visitor); } public ComponentAdapter getDelegate() { return ca.getDelegate(); } public U findAdapterOfType(Class adapterType) { return ca.findAdapterOfType(adapterType); } public String getDescriptor() { return null; } } /** {@inheritDoc} **/ public ComponentAdapter getComponentAdapter(final Class componentType, final NameBinding componentNameBinding) { return getComponentAdapter(componentType, componentNameBinding, null); } /** {@inheritDoc} **/ private ComponentAdapter getComponentAdapter(final Class componentType, final NameBinding componentNameBinding, final Class binding) { // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115 ComponentAdapter adapterByKey = getComponentAdapter(componentType); if (adapterByKey != null) { return typeComponentAdapter(adapterByKey); } List> found = binding == null ? getComponentAdapters(componentType) : getComponentAdapters(componentType, binding); if (found.size() == 1) { return found.get(0); } else if (found.isEmpty()) { if (parent != null) { return getParent().getComponentAdapter(componentType, componentNameBinding); } else { return null; } } else { if (componentNameBinding != null) { String parameterName = componentNameBinding.getName(); if (parameterName != null) { ComponentAdapter ca = getComponentAdapter(parameterName); if (ca != null && componentType.isAssignableFrom(ca.getComponentImplementation())) { return typeComponentAdapter(ca); } } } String[] foundStrings = makeFoundAmbiguousStrings(found); throw new AbstractInjector.AmbiguousComponentResolutionException(componentType, foundStrings); } } /** {@inheritDoc} **/ public ComponentAdapter getComponentAdapter(final Class componentType, final Class binding) { // 1 return getComponentAdapter(componentType, null, binding); } /** {@inheritDoc} **/ public List> getComponentAdapters(final Class componentType) { return getComponentAdapters(componentType, null); } /** {@inheritDoc} **/ public List> getComponentAdapters(final Class componentType, final Class binding) { if (componentType == null) { return Collections.emptyList(); } List> found = new ArrayList>(); for (ComponentAdapter componentAdapter : getComponentAdapters()) { Object k = componentAdapter.getComponentKey(); if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation()) && (!(k instanceof BindKey) || (k instanceof BindKey && (((BindKey)k).getAnnotation() == null || binding == null || ((BindKey)k).getAnnotation() == binding)))) { found.add((ComponentAdapter)typeComponentAdapter(componentAdapter)); } } return found; } protected MutablePicoContainer addAdapterInternal(ComponentAdapter componentAdapter) { Object componentKey = componentAdapter.getComponentKey(); if (getComponentKeyToAdapterCache().containsKey(componentKey)) { throw new PicoCompositionException("Duplicate Keys not allowed. Duplicate for '" + componentKey + "'"); } getModifiableComponentAdapterList().add(componentAdapter); getComponentKeyToAdapterCache().put(componentKey, componentAdapter); return this; } /** * {@inheritDoc} * This method can be used to override the ComponentAdapter created by the {@link ComponentFactory} * passed to the constructor of this container. */ public MutablePicoContainer addAdapter(final ComponentAdapter componentAdapter) { return addAdapter(componentAdapter, this.containerProperties); } /** {@inheritDoc} **/ public MutablePicoContainer addAdapter(final ComponentAdapter componentAdapter, final Properties properties) { Properties tmpProperties = (Properties)properties.clone(); AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.USE_NAMES); if (AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.NONE) == false && componentFactory instanceof BehaviorFactory) { MutablePicoContainer container = addAdapterInternal(((BehaviorFactory)componentFactory).addComponentAdapter( componentMonitor, lifecycleStrategy, tmpProperties, componentAdapter)); throwIfPropertiesLeft(tmpProperties); return container; } else { return addAdapterInternal(componentAdapter); } } /** {@inheritDoc} **/ public ComponentAdapter removeComponent(final Object componentKey) { lifecycleState.removingComponent(); ComponentAdapter adapter = (ComponentAdapter) getComponentKeyToAdapterCache().remove(componentKey); getModifiableComponentAdapterList().remove(adapter); getOrderedComponentAdapters().remove(adapter); return adapter; } /** * {@inheritDoc} * The returned ComponentAdapter will be an {@link org.picocontainer.adapters.InstanceAdapter}. */ public MutablePicoContainer addComponent(final Object implOrInstance) { return addComponent(implOrInstance, this.containerProperties); } private MutablePicoContainer addComponent(final Object implOrInstance, final Properties props) { Class clazz; if (implOrInstance instanceof String) { return addComponent(implOrInstance, implOrInstance); } if (implOrInstance instanceof Class) { clazz = (Class)implOrInstance; } else { clazz = implOrInstance.getClass(); } return addComponent(clazz, implOrInstance, props); } public MutablePicoContainer addConfig(final String name, final Object val) { return addAdapterInternal(new InstanceAdapter(name, val, lifecycleStrategy, componentMonitor)); } /** * {@inheritDoc} * The returned ComponentAdapter will be instantiated by the {@link ComponentFactory} * passed to the container's constructor. */ public MutablePicoContainer addComponent(final Object componentKey, final Object componentImplementationOrInstance, final Parameter... parameters) { return this.addComponent(componentKey, componentImplementationOrInstance, this.containerProperties, parameters); } private MutablePicoContainer addComponent(final Object componentKey, final Object componentImplementationOrInstance, final Properties properties, Parameter... parameters) { if (parameters != null && parameters.length == 0) { parameters = null; // backwards compatibility! solve this better later - Paul } //New replacement for Parameter.ZERO. if (parameters != null && parameters.length == 1 && DefaultConstructorParameter.INSTANCE.equals(parameters[0])) { parameters = new Parameter[0]; } if (componentImplementationOrInstance instanceof Class) { Properties tmpProperties = (Properties) properties.clone(); ComponentAdapter adapter = componentFactory.createComponentAdapter(componentMonitor, lifecycleStrategy, tmpProperties, componentKey, (Class)componentImplementationOrInstance, parameters); AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.USE_NAMES); throwIfPropertiesLeft(tmpProperties); if (lifecycleState.isStarted()) { addAdapterIfStartable(adapter); potentiallyStartAdapter(adapter); } return addAdapterInternal(adapter); } else { ComponentAdapter adapter = new InstanceAdapter(componentKey, componentImplementationOrInstance, lifecycleStrategy, componentMonitor); if (lifecycleState.isStarted()) { addAdapterIfStartable(adapter); potentiallyStartAdapter(adapter); } return addAdapter(adapter, properties); } } private void throwIfPropertiesLeft(final Properties tmpProperties) { if(tmpProperties.size() > 0) { throw new PicoCompositionException("Unprocessed Characteristics:" + tmpProperties +", please refer to http://picocontainer.org/unprocessed-properties-help.html"); } } private synchronized void addOrderedComponentAdapter(final ComponentAdapter componentAdapter) { if (!getOrderedComponentAdapters().contains(componentAdapter)) { getOrderedComponentAdapters().add(componentAdapter); } } public List getComponents() throws PicoException { return getComponents(Object.class); } public List getComponents(final Class componentType) { if (componentType == null) { return Collections.emptyList(); } Map, T> adapterToInstanceMap = new HashMap, T>(); List result = new ArrayList(); synchronized(this) { for (ComponentAdapter componentAdapter : getModifiableComponentAdapterList()) { if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) { ComponentAdapter typedComponentAdapter = typeComponentAdapter(componentAdapter); T componentInstance = getLocalInstance(typedComponentAdapter); adapterToInstanceMap.put(typedComponentAdapter, componentInstance); } } for (ComponentAdapter componentAdapter : getOrderedComponentAdapters()) { final T componentInstance = adapterToInstanceMap.get(componentAdapter); if (componentInstance != null) { // may be null in the case of the "implicit" addAdapter // representing "this". result.add(componentInstance); } } } return result; } private T getLocalInstance(final ComponentAdapter typedComponentAdapter) { T componentInstance = typedComponentAdapter.getComponentInstance(this, ComponentAdapter.NOTHING.class); // This is to ensure all are added. (Indirect dependencies will be added // from InstantiatingComponentAdapter). addOrderedComponentAdapter(typedComponentAdapter); return componentInstance; } @SuppressWarnings({ "unchecked" }) private static ComponentAdapter typeComponentAdapter(final ComponentAdapter componentAdapter) { return (ComponentAdapter)componentAdapter; } public Object getComponent(final Object componentKeyOrType) { return getComponent(componentKeyOrType, null); } public Object getComponent(final Object componentKeyOrType, Type into) { synchronized (this) { if (intoThreadLocal == null) { intoThreadLocal = new IntoThreadLocal(); } } intoThreadLocal.set(into); try { return getComponent(componentKeyOrType, (Class) null); } finally { intoThreadLocal.set(null); } } public Object getComponent(final Object componentKeyOrType, final Class annotation) { ComponentAdapter componentAdapter = null; Object component; try { if (annotation != null) { componentAdapter = getComponentAdapter((Class)componentKeyOrType, annotation); component = componentAdapter == null ? null : getInstance(componentAdapter, null); } else if (componentKeyOrType instanceof Class) { componentAdapter = getComponentAdapter((Class)componentKeyOrType, (NameBinding) null); component = componentAdapter == null ? null : getInstance(componentAdapter, (Class)componentKeyOrType); } else { componentAdapter = getComponentAdapter(componentKeyOrType); component = componentAdapter == null ? null : getInstance(componentAdapter, null); } } catch (AbstractInjector.AmbiguousComponentResolutionException e) { if (componentAdapter != null) { e.setComponent(findInjectorOrInstanceAdapter(componentAdapter).toString()); } throw e; } return decorateComponent(component, componentAdapter); } /** * This is invoked when getComponent(..) is called. It allows extendees to decorate a * component before it is returned to the caller. * @param component the component that will be returned for getComponent(..) * @param componentAdapter the component adapter that made that component * @return the component (the same as that passed in by default) */ protected Object decorateComponent(Object component, ComponentAdapter componentAdapter) { if (componentAdapter instanceof ComponentLifecycle && lifecycleStrategy.isLazy(componentAdapter) // is Lazy && !((ComponentLifecycle) componentAdapter).isStarted()) { ((ComponentLifecycle)componentAdapter).start(this); } return component; } public T getComponent(final Class componentType) { Object o = getComponent((Object)componentType, null); return componentType.cast(o); } public T getComponent(final Class componentType, final Class binding) { Object o = getComponent((Object)componentType, binding); return componentType.cast(o); } private Object getInstance(final ComponentAdapter componentAdapter, Class componentKey) { // check whether this is our adapter // we need to check this to ensure up-down dependencies cannot be followed final boolean isLocal = getModifiableComponentAdapterList().contains(componentAdapter); if (isLocal || componentAdapter instanceof LateInstance) { Object instance; try { if (componentAdapter instanceof FactoryInjector) { instance = ((FactoryInjector) componentAdapter).getComponentInstance(this, getInto()); } else { instance = componentAdapter.getComponentInstance(this, getInto()); } } catch (AbstractInjector.CyclicDependencyException e) { if (parent != null) { instance = getParent().getComponent(componentAdapter.getComponentKey()); if (instance != null) { return instance; } } throw e; } addOrderedComponentAdapter(componentAdapter); return instance; } else if (parent != null) { Object key = componentKey; if (key == null) { key = componentAdapter.getComponentKey(); } return getParent().getComponent(key); } return null; } private Type getInto() { if (intoThreadLocal == null) { return null; } return intoThreadLocal.get(); } /** {@inheritDoc} **/ public PicoContainer getParent() { return parent; } /** {@inheritDoc} **/ public ComponentAdapter removeComponentByInstance(final T componentInstance) { for (ComponentAdapter componentAdapter : getModifiableComponentAdapterList()) { if (getLocalInstance(componentAdapter).equals(componentInstance)) { return removeComponent(componentAdapter.getComponentKey()); } } return null; } /** * Start the components of this PicoContainer and all its logical child containers. * The starting of the child container is only attempted if the parent * container start successfully. The child container for which start is attempted * is tracked so that upon stop, only those need to be stopped. * The lifecycle operation is delegated to the component adapter, * if it is an instance of {@link Behavior lifecycle manager}. * The actual {@link LifecycleStrategy lifecycle strategy} supported * depends on the concrete implementation of the adapter. * * @see Behavior * @see LifecycleStrategy * @see #makeChildContainer() * @see #addChildContainer(PicoContainer) * @see #removeChildContainer(PicoContainer) */ public synchronized void start() { lifecycleState.starting(); startAdapters(); childrenStarted.clear(); for (PicoContainer child : children) { childrenStarted.add(new WeakReference(child)); if (child instanceof Startable) { ((Startable)child).start(); } } } /** * Stop the components of this PicoContainer and all its logical child containers. * The stopping of the child containers is only attempted for those that have been * started, possibly not successfully. * The lifecycle operation is delegated to the component adapter, * if it is an instance of {@link Behavior lifecycle manager}. * The actual {@link LifecycleStrategy lifecycle strategy} supported * depends on the concrete implementation of the adapter. * * @see Behavior * @see LifecycleStrategy * @see #makeChildContainer() * @see #addChildContainer(PicoContainer) * @see #removeChildContainer(PicoContainer) */ public synchronized void stop() { lifecycleState.stopping(); for (PicoContainer child : children) { if (childStarted(child)) { if (child instanceof Startable) { ((Startable)child).stop(); } } } stopAdapters(); lifecycleState.stopped(); } /** * Checks the status of the child container to see if it's been started * to prevent IllegalStateException upon stop * * @param child the child PicoContainer * * @return A boolean, true if the container is started */ private boolean childStarted(final PicoContainer child) { for (WeakReference eachChild : childrenStarted) { PicoContainer ref = eachChild.get(); if (ref == null) { continue; } if (child.equals(ref)) { return true; } } return false; } /** * Dispose the components of this PicoContainer and all its logical child containers. * The lifecycle operation is delegated to the component adapter, * if it is an instance of {@link Behavior lifecycle manager}. * The actual {@link LifecycleStrategy lifecycle strategy} supported * depends on the concrete implementation of the adapter. * * @see Behavior * @see LifecycleStrategy * @see #makeChildContainer() * @see #addChildContainer(PicoContainer) * @see #removeChildContainer(PicoContainer) */ public synchronized void dispose() { if (lifecycleState.isStarted()) { stop(); } lifecycleState.disposing(); for (PicoContainer child : children) { if (child instanceof MutablePicoContainer) { ((Disposable)child).dispose(); } } disposeAdapters(); lifecycleState.disposed(); } public synchronized void setLifecycleState(LifecycleState lifecycleState) { this.lifecycleState = lifecycleState; } public MutablePicoContainer makeChildContainer() { DefaultPicoContainer pc = new DefaultPicoContainer(componentFactory, lifecycleStrategy, this, componentMonitor); addChildContainer(pc); return pc; } /** * Checks for identical references in the child container. It doesn't * traverse an entire hierarchy, namely it simply checks for child containers * that are equal to the current container. * @param child */ private void checkCircularChildDependencies(PicoContainer child) { final String MESSAGE = "Cannot have circular dependency between parent %s and child: %s"; if (child == this) { throw new IllegalArgumentException(String.format(MESSAGE,this,child)); } //Todo: Circular Import Dependency on AbstractDelegatingPicoContainer if (child instanceof AbstractDelegatingPicoContainer) { AbstractDelegatingPicoContainer delegateChild = (AbstractDelegatingPicoContainer) child; while(delegateChild != null) { PicoContainer delegateInstance = delegateChild.getDelegate(); if (this == delegateInstance) { throw new IllegalArgumentException(String.format(MESSAGE,this,child)); } if (delegateInstance instanceof AbstractDelegatingPicoContainer) { delegateChild = (AbstractDelegatingPicoContainer) delegateInstance; } else { delegateChild = null; } } } } public MutablePicoContainer addChildContainer(final PicoContainer child) { checkCircularChildDependencies(child); if (children.add(child)) { // TODO Should only be added if child container has also be started if (lifecycleState.isStarted()) { childrenStarted.add(new WeakReference(child)); } } return this; } public boolean removeChildContainer(final PicoContainer child) { final boolean result = children.remove(child); WeakReference foundRef = null; for (WeakReference eachChild : childrenStarted) { PicoContainer ref = eachChild.get(); if (ref.equals(child)) { foundRef = eachChild; break; } } if (foundRef != null) { childrenStarted.remove(foundRef); } return result; } public MutablePicoContainer change(final Properties... properties) { for (Properties c : properties) { Enumeration e = (Enumeration) c.propertyNames(); while (e.hasMoreElements()) { String s = e.nextElement(); containerProperties.setProperty(s,c.getProperty(s)); } } return this; } public MutablePicoContainer as(final Properties... properties) { return new AsPropertiesPicoContainer(properties); } public void accept(final PicoVisitor visitor) { //TODO Pico 3 : change accept signatures to allow abort at any point in the traversal. boolean shouldContinue = visitor.visitContainer(this); if (!shouldContinue) { return; } componentFactory.accept(visitor); // will cascade through behaviors final List> componentAdapters = new ArrayList>(getComponentAdapters()); for (ComponentAdapter componentAdapter : componentAdapters) { componentAdapter.accept(visitor); } final List allChildren = new ArrayList(children); for (PicoContainer child : allChildren) { child.accept(visitor); } } /** * Changes monitor in the ComponentFactory, the component adapters * and the child containers, if these support a ComponentMonitorStrategy. * {@inheritDoc} */ public void changeMonitor(final ComponentMonitor monitor) { this.componentMonitor = monitor; if (lifecycleStrategy instanceof ComponentMonitorStrategy) { ((ComponentMonitorStrategy)lifecycleStrategy).changeMonitor(monitor); } for (ComponentAdapter adapter : getModifiableComponentAdapterList()) { if (adapter instanceof ComponentMonitorStrategy) { ((ComponentMonitorStrategy)adapter).changeMonitor(monitor); } } for (PicoContainer child : children) { if (child instanceof ComponentMonitorStrategy) { ((ComponentMonitorStrategy)child).changeMonitor(monitor); } } } /** * Returns the first current monitor found in the ComponentFactory, the component adapters * and the child containers, if these support a ComponentMonitorStrategy. * {@inheritDoc} * * @throws PicoCompositionException if no component monitor is found in container or its children */ public ComponentMonitor currentMonitor() { return componentMonitor; } /** * Loops over all component adapters and invokes * start(PicoContainer) method on the ones which are LifecycleManagers */ private void startAdapters() { Collection> adapters = getComponentAdapters(); for (ComponentAdapter adapter : adapters) { addAdapterIfStartable(adapter); } adapters = getOrderedComponentAdapters(); // clone the adapters List> adaptersClone = new ArrayList>(adapters); for (final ComponentAdapter adapter : adaptersClone) { potentiallyStartAdapter(adapter); } } protected void potentiallyStartAdapter(ComponentAdapter adapter) { if (adapter instanceof ComponentLifecycle) { if (!lifecycleStrategy.isLazy(adapter)) { ((ComponentLifecycle)adapter).start(this); } } } private void addAdapterIfStartable(ComponentAdapter adapter) { if (adapter instanceof ComponentLifecycle) { ComponentLifecycle componentLifecycle = (ComponentLifecycle)adapter; if (componentLifecycle.componentHasLifecycle()) { // create an instance, it will be added to the ordered CA list instantiateComponentAsIsStartable(adapter); addOrderedComponentAdapter(adapter); } } } protected void instantiateComponentAsIsStartable(ComponentAdapter adapter) { if (!lifecycleStrategy.isLazy(adapter)) { adapter.getComponentInstance(DefaultPicoContainer.this, ComponentAdapter.NOTHING.class); } } /** * Loops over started component adapters (in inverse order) and invokes * stop(PicoContainer) method on the ones which are LifecycleManagers */ private void stopAdapters() { for (int i = getOrderedComponentAdapters().size() - 1; 0 <= i; i--) { ComponentAdapter adapter = getOrderedComponentAdapters().get(i); if (adapter instanceof ComponentLifecycle) { ComponentLifecycle componentLifecycle = (ComponentLifecycle)adapter; if (componentLifecycle.componentHasLifecycle() && componentLifecycle.isStarted()) { componentLifecycle.stop(DefaultPicoContainer.this); } } } } /** * Loops over all component adapters (in inverse order) and invokes * dispose(PicoContainer) method on the ones which are LifecycleManagers */ private void disposeAdapters() { for (int i = getOrderedComponentAdapters().size() - 1; 0 <= i; i--) { ComponentAdapter adapter = getOrderedComponentAdapters().get(i); if (adapter instanceof ComponentLifecycle) { ComponentLifecycle componentLifecycle = (ComponentLifecycle)adapter; componentLifecycle.dispose(DefaultPicoContainer.this); } } } /** * @return the orderedComponentAdapters */ protected List> getOrderedComponentAdapters() { return orderedComponentAdapters; } /** * @return the componentKeyToAdapterCache */ protected Map> getComponentKeyToAdapterCache() { return componentKeyToAdapterCache; } /** * @return the componentAdapters */ protected Set> getModifiableComponentAdapterList() { return componentAdapters; } public synchronized void setName(String name) { this.name = name; } @Override public String toString() { return String.format("%s:%d<%s", (name != null ? name : super.toString()), this.componentAdapters.size(), (parent != null && !(parent instanceof EmptyPicoContainer)? parent.toString() : "|")); } /** * If this container has a set of converters, then return it. * If it does not, and the parent (or their parent ..) does, use that * If they do not, return a NullObject implementation (ConversNothing) * @return the converters */ public synchronized Converters getConverters() { if (converters == null) { if (parent == null || (parent instanceof Converting && ((Converting) parent).getConverters() instanceof ConvertsNothing)) { converters = new BuiltInConverters(); } else { return ((Converting) parent).getConverters(); } } return converters; } @SuppressWarnings("synthetic-access") private class AsPropertiesPicoContainer extends AbstractDelegatingMutablePicoContainer { private final Properties properties; public AsPropertiesPicoContainer(final Properties... props) { super(DefaultPicoContainer.this); properties = (Properties) containerProperties.clone(); for (Properties c : props) { Enumeration e = c.propertyNames(); while (e.hasMoreElements()) { String s = (String)e.nextElement(); properties.setProperty(s,c.getProperty(s)); } } } @Override @SuppressWarnings("unused") public MutablePicoContainer as( Properties... props) { throw new PicoCompositionException("Syntax 'as(FOO).as(BAR)' not allowed, do 'as(FOO, BAR)' instead"); } @Override public MutablePicoContainer makeChildContainer() { return getDelegate().makeChildContainer(); } @Override public MutablePicoContainer addComponent(final Object componentKey, final Object componentImplementationOrInstance, final Parameter... parameters) throws PicoCompositionException { return DefaultPicoContainer.this.addComponent(componentKey, componentImplementationOrInstance, properties, parameters); } @Override public MutablePicoContainer addComponent(final Object implOrInstance) throws PicoCompositionException { return DefaultPicoContainer.this.addComponent(implOrInstance, properties); } @Override public MutablePicoContainer addAdapter(final ComponentAdapter componentAdapter) throws PicoCompositionException { return DefaultPicoContainer.this.addAdapter(componentAdapter, properties); } /** * {@inheritDoc} * @see org.picocontainer.MutablePicoContainer#getLifecycleState() */ @Override public LifecycleState getLifecycleState() { return DefaultPicoContainer.this.getLifecycleState(); } /** * {@inheritDoc} * @see org.picocontainer.MutablePicoContainer#getName() */ @Override public String getName() { return DefaultPicoContainer.this.getName(); } } private static class IntoThreadLocal extends ThreadLocal implements Serializable { @Override protected Type initialValue() { return ComponentAdapter.NOTHING.class; } } /** * {@inheritDoc} * @see org.picocontainer.MutablePicoContainer#getLifecycleState() */ public synchronized LifecycleState getLifecycleState() { return lifecycleState; } /** * {@inheritDoc} * @see org.picocontainer.MutablePicoContainer#getName() */ public synchronized String getName() { return this.name; } }