Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.picocontainer.DefaultPicoContainer Maven / Gradle / Ivy
/*****************************************************************************
* 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 extends T> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation>) null);
} finally {
intoThreadLocal.set(null);
}
}
public Object getComponent(final Object componentKeyOrType, final Class extends Annotation> 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 extends Annotation> 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;
}
}