0001: /*****************************************************************************
0002: * Copyright (C) PicoContainer Organization. All rights reserved. *
0003: * ------------------------------------------------------------------------- *
0004: * The software in this package is published under the terms of the BSD *
0005: * style license a copy of which has been included with this distribution in *
0006: * the LICENSE.txt file. *
0007: * *
0008: * Original code by *
0009: *****************************************************************************/package org.picocontainer;
0010:
0011: import java.io.Serializable;
0012: import java.lang.annotation.Annotation;
0013: import java.lang.ref.WeakReference;
0014: import java.util.ArrayList;
0015: import java.util.Collection;
0016: import java.util.Collections;
0017: import java.util.Enumeration;
0018: import java.util.HashMap;
0019: import java.util.HashSet;
0020: import java.util.List;
0021: import java.util.Map;
0022: import java.util.Properties;
0023: import java.util.Set;
0024:
0025: import org.picocontainer.adapters.InstanceAdapter;
0026: import org.picocontainer.behaviors.AbstractBehaviorFactory;
0027: import org.picocontainer.behaviors.AdaptingBehavior;
0028: import org.picocontainer.behaviors.Cached;
0029: import org.picocontainer.behaviors.Caching;
0030: import org.picocontainer.behaviors.HiddenImplementation;
0031: import org.picocontainer.containers.AbstractDelegatingMutablePicoContainer;
0032: import org.picocontainer.containers.AbstractDelegatingPicoContainer;
0033: import org.picocontainer.containers.EmptyPicoContainer;
0034: import org.picocontainer.containers.ImmutablePicoContainer;
0035: import org.picocontainer.injectors.AbstractInjector;
0036: import org.picocontainer.injectors.AdaptingInjection;
0037: import org.picocontainer.lifecycle.LifecycleState;
0038: import static org.picocontainer.lifecycle.LifecycleState.*;
0039: import org.picocontainer.lifecycle.StartableLifecycleStrategy;
0040: import org.picocontainer.monitors.NullComponentMonitor;
0041:
0042: /**
0043: * <p/>
0044: * The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation.
0045: * Constructing a container c with a parent p container will cause c to look up components
0046: * in p if they cannot be found inside c itself.
0047: * </p>
0048: * <p/>
0049: * Using {@link Class} objects as keys to the various registerXXX() methods makes
0050: * a subtle semantic difference:
0051: * </p>
0052: * <p/>
0053: * If there are more than one registered components of the same type and one of them are
0054: * registered with a {@link java.lang.Class} key of the corresponding type, this addComponent
0055: * will take precedence over other components during type resolution.
0056: * </p>
0057: * <p/>
0058: * Another place where keys that are classes make a subtle difference is in
0059: * {@link HiddenImplementation}.
0060: * </p>
0061: * <p/>
0062: * This implementation of {@link MutablePicoContainer} also supports
0063: * {@link ComponentMonitorStrategy}.
0064: * </p>
0065: *
0066: * @author Paul Hammant
0067: * @author Aslak Hellesøy
0068: * @author Jon Tirsén
0069: * @author Thomas Heller
0070: * @author Mauro Talevi
0071: */
0072: public class DefaultPicoContainer implements MutablePicoContainer,
0073: ComponentMonitorStrategy, Serializable {
0074:
0075: /**
0076: * Serialization UUID.
0077: */
0078: private static final long serialVersionUID = -8987815732600681148L;
0079:
0080: /**
0081: * Component factory instance.
0082: */
0083: private final ComponentFactory componentFactory;
0084:
0085: /**
0086: * Parent picocontainer
0087: */
0088: private PicoContainer parent;
0089:
0090: /**
0091: * All picocontainer children.
0092: */
0093: private final Set<PicoContainer> children = new HashSet<PicoContainer>();
0094:
0095: /**
0096: * Current state of the container.
0097: */
0098: private LifecycleState lifecycleState = CONSTRUCTED;
0099:
0100: /**
0101: * Keeps track of child containers started status.
0102: */
0103: private final Set<WeakReference<PicoContainer>> childrenStarted = new HashSet<WeakReference<PicoContainer>>();
0104:
0105: /**
0106: * Lifecycle strategy instance.
0107: */
0108: private final LifecycleStrategy lifecycleStrategy;
0109:
0110: private final Properties componentProperties = new Properties();
0111:
0112: /**
0113: * Component monitor instance. Receives event callbacks.
0114: */
0115: private ComponentMonitor componentMonitor;
0116:
0117: /** List collecting the CAs which have been successfully started */
0118: private final List<WeakReference<ComponentAdapter<?>>> startedComponentAdapters = new ArrayList<WeakReference<ComponentAdapter<?>>>();
0119:
0120: /**
0121: * Map used for looking up component adapters by their key.
0122: */
0123: private final Map<Object, ComponentAdapter<?>> componentKeyToAdapterCache = new HashMap<Object, ComponentAdapter<?>>();
0124:
0125: private final List<ComponentAdapter<?>> componentAdapters = new ArrayList<ComponentAdapter<?>>();
0126:
0127: protected final List<ComponentAdapter<?>> orderedComponentAdapters = new ArrayList<ComponentAdapter<?>>();
0128:
0129: /**
0130: * Creates a new container with a custom ComponentFactory and a parent container.
0131: * <p/>
0132: * <em>
0133: * Important note about caching: If you intend the components to be cached, you should pass
0134: * in a factory that creates {@link Cached} instances, such as for example
0135: * {@link Caching}. Caching can delegate to
0136: * other ComponentAdapterFactories.
0137: * </em>
0138: *
0139: * @param componentFactory the factory to use for creation of ComponentAdapters.
0140: * @param parent the parent container (used for component dependency lookups).
0141: */
0142: public DefaultPicoContainer(
0143: final ComponentFactory componentFactory,
0144: final PicoContainer parent) {
0145: this (componentFactory, new StartableLifecycleStrategy(
0146: new NullComponentMonitor()), parent,
0147: new NullComponentMonitor());
0148: }
0149:
0150: /**
0151: * Creates a new container with a custom ComponentFactory, LifecycleStrategy for instance registration,
0152: * and a parent container.
0153: * <p/>
0154: * <em>
0155: * Important note about caching: If you intend the components to be cached, you should pass
0156: * in a factory that creates {@link Cached} instances, such as for example
0157: * {@link Caching}. Caching can delegate to
0158: * other ComponentAdapterFactories.
0159: * </em>
0160: *
0161: * @param componentFactory the factory to use for creation of ComponentAdapters.
0162: * @param lifecycleStrategy
0163: * the lifecycle strategy chosen for registered
0164: * instance (not implementations!)
0165: * @param parent the parent container (used for component dependency lookups).
0166: */
0167: public DefaultPicoContainer(
0168: final ComponentFactory componentFactory,
0169: final LifecycleStrategy lifecycleStrategy,
0170: final PicoContainer parent) {
0171: this (componentFactory, lifecycleStrategy, parent,
0172: new NullComponentMonitor());
0173: }
0174:
0175: public DefaultPicoContainer(
0176: final ComponentFactory componentFactory,
0177: final LifecycleStrategy lifecycleStrategy,
0178: final PicoContainer parent,
0179: final ComponentMonitor componentMonitor) {
0180: if (componentFactory == null) {
0181: throw new NullPointerException("componentFactory");
0182: }
0183: if (lifecycleStrategy == null) {
0184: throw new NullPointerException("lifecycleStrategy");
0185: }
0186: this .componentFactory = componentFactory;
0187: this .lifecycleStrategy = lifecycleStrategy;
0188: this .parent = parent;
0189: if (parent != null && !(parent instanceof EmptyPicoContainer)) {
0190: this .parent = new ImmutablePicoContainer(parent);
0191: }
0192: this .componentMonitor = componentMonitor;
0193: }
0194:
0195: /**
0196: * Creates a new container with the AdaptingInjection using a
0197: * custom ComponentMonitor
0198: *
0199: * @param monitor the ComponentMonitor to use
0200: * @param parent the parent container (used for component dependency lookups).
0201: */
0202: public DefaultPicoContainer(final ComponentMonitor monitor,
0203: final PicoContainer parent) {
0204: this (new AdaptingBehavior(), new StartableLifecycleStrategy(
0205: monitor), parent, monitor);
0206: }
0207:
0208: /**
0209: * Creates a new container with the AdaptingInjection using a
0210: * custom ComponentMonitor and lifecycle strategy
0211: *
0212: * @param monitor the ComponentMonitor to use
0213: * @param lifecycleStrategy the lifecycle strategy to use.
0214: * @param parent the parent container (used for component dependency lookups).
0215: */
0216: public DefaultPicoContainer(final ComponentMonitor monitor,
0217: final LifecycleStrategy lifecycleStrategy,
0218: final PicoContainer parent) {
0219: this (new AdaptingBehavior(), lifecycleStrategy, parent, monitor);
0220: }
0221:
0222: /**
0223: * Creates a new container with the AdaptingInjection using a
0224: * custom lifecycle strategy
0225: *
0226: * @param lifecycleStrategy the lifecycle strategy to use.
0227: * @param parent the parent container (used for component dependency lookups).
0228: */
0229: public DefaultPicoContainer(
0230: final LifecycleStrategy lifecycleStrategy,
0231: final PicoContainer parent) {
0232: this (new NullComponentMonitor(), lifecycleStrategy, parent);
0233: }
0234:
0235: /**
0236: * Creates a new container with a custom ComponentFactory and no parent container.
0237: *
0238: * @param componentFactory the ComponentFactory to use.
0239: */
0240: public DefaultPicoContainer(final ComponentFactory componentFactory) {
0241: this (componentFactory, null);
0242: }
0243:
0244: /**
0245: * Creates a new container with the AdaptingInjection using a
0246: * custom ComponentMonitor
0247: *
0248: * @param monitor the ComponentMonitor to use
0249: */
0250: public DefaultPicoContainer(final ComponentMonitor monitor) {
0251: this (monitor, new StartableLifecycleStrategy(monitor), null);
0252: }
0253:
0254: /**
0255: * Creates a new container with a (caching) {@link AdaptingInjection}
0256: * and a parent container.
0257: *
0258: * @param parent the parent container (used for component dependency lookups).
0259: */
0260: public DefaultPicoContainer(final PicoContainer parent) {
0261: this (new AdaptingBehavior(), parent);
0262: }
0263:
0264: /** Creates a new container with a {@link AdaptingBehavior} and no parent container. */
0265: public DefaultPicoContainer() {
0266: this (new AdaptingBehavior(), null);
0267: }
0268:
0269: /** {@inheritDoc} **/
0270: public Collection<ComponentAdapter<?>> getComponentAdapters() {
0271: return Collections
0272: .unmodifiableList(getModifiableComponentAdapterList());
0273: }
0274:
0275: /** {@inheritDoc} **/
0276: public final ComponentAdapter<?> getComponentAdapter(
0277: final Object componentKey) {
0278: ComponentAdapter<?> adapter = getComponentKeyToAdapterCache()
0279: .get(componentKey);
0280: if (adapter == null && parent != null) {
0281: adapter = parent.getComponentAdapter(componentKey);
0282: }
0283: return adapter;
0284: }
0285:
0286: /** {@inheritDoc} **/
0287: public <T> ComponentAdapter<T> getComponentAdapter(
0288: final Class<T> componentType,
0289: final NameBinding componentNameBinding) {
0290: return getComponentAdapter(componentType, componentNameBinding,
0291: null);
0292: }
0293:
0294: /** {@inheritDoc} **/
0295: private <T> ComponentAdapter<T> getComponentAdapter(
0296: final Class<T> componentType,
0297: final NameBinding componentNameBinding,
0298: final Class<? extends Annotation> binding) {
0299: // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
0300: ComponentAdapter<?> adapterByKey = getComponentAdapter(componentType);
0301: if (adapterByKey != null) {
0302: return typeComponentAdapter(adapterByKey);
0303: }
0304:
0305: List<ComponentAdapter<T>> found = binding == null ? getComponentAdapters(componentType)
0306: : getComponentAdapters(componentType, binding);
0307:
0308: if (found.size() == 1) {
0309: return found.get(0);
0310: } else if (found.isEmpty()) {
0311: if (parent != null) {
0312: return parent.getComponentAdapter(componentType,
0313: componentNameBinding);
0314: } else {
0315: return null;
0316: }
0317: } else {
0318: if (componentNameBinding != null) {
0319: String parameterName = componentNameBinding.getName();
0320: if (parameterName != null) {
0321: ComponentAdapter<?> ca = getComponentAdapter(parameterName);
0322: if (ca != null
0323: && componentType.isAssignableFrom(ca
0324: .getComponentImplementation())) {
0325: return typeComponentAdapter(ca);
0326: }
0327: }
0328: }
0329: Class<?>[] foundClasses = new Class[found.size()];
0330: for (int i = 0; i < foundClasses.length; i++) {
0331: foundClasses[i] = found.get(i)
0332: .getComponentImplementation();
0333: }
0334:
0335: throw new AbstractInjector.AmbiguousComponentResolutionException(
0336: componentType, foundClasses);
0337: }
0338: }
0339:
0340: /** {@inheritDoc} **/
0341: public <T> ComponentAdapter<T> getComponentAdapter(
0342: final Class<T> componentType,
0343: final Class<? extends Annotation> binding) {
0344: return getComponentAdapter(componentType, null, binding);
0345: }
0346:
0347: /** {@inheritDoc} **/
0348: public <T> List<ComponentAdapter<T>> getComponentAdapters(
0349: final Class<T> componentType) {
0350: return getComponentAdapters(componentType, null);
0351: }
0352:
0353: /** {@inheritDoc} **/
0354: public <T> List<ComponentAdapter<T>> getComponentAdapters(
0355: final Class<T> componentType,
0356: final Class<? extends Annotation> binding) {
0357: if (componentType == null) {
0358: return Collections.emptyList();
0359: }
0360: List<ComponentAdapter<T>> found = new ArrayList<ComponentAdapter<T>>();
0361: for (ComponentAdapter<?> componentAdapter : getComponentAdapters()) {
0362: Object k = componentAdapter.getComponentKey();
0363:
0364: if (componentType.isAssignableFrom(componentAdapter
0365: .getComponentImplementation())
0366: && (!(k instanceof BindKey) || (k instanceof BindKey && (((BindKey<?>) k)
0367: .getAnnotation() == null
0368: || binding == null || ((BindKey<?>) k)
0369: .getAnnotation() == binding)))) {
0370: found
0371: .add((ComponentAdapter<T>) typeComponentAdapter(componentAdapter));
0372: }
0373: }
0374: return found;
0375: }
0376:
0377: protected MutablePicoContainer addAdapterInternal(
0378: final ComponentAdapter<?> componentAdapter) {
0379: Object componentKey = componentAdapter.getComponentKey();
0380: if (getComponentKeyToAdapterCache().containsKey(componentKey)) {
0381: throw new PicoCompositionException(
0382: "Duplicate Keys not allowed. Duplicate for '"
0383: + componentKey + "'");
0384: }
0385: getModifiableComponentAdapterList().add(componentAdapter);
0386: getComponentKeyToAdapterCache().put(componentKey,
0387: componentAdapter);
0388: return this ;
0389: }
0390:
0391: /**
0392: * {@inheritDoc}
0393: * This method can be used to override the ComponentAdapter created by the {@link ComponentFactory}
0394: * passed to the constructor of this container.
0395: */
0396: public MutablePicoContainer addAdapter(
0397: final ComponentAdapter<?> componentAdapter) {
0398: return addAdapter(componentAdapter, this .componentProperties);
0399: }
0400:
0401: /** {@inheritDoc} **/
0402: public MutablePicoContainer addAdapter(
0403: final ComponentAdapter<?> componentAdapter,
0404: final Properties properties) {
0405: Properties tmpProperties = (Properties) properties.clone();
0406: if (AbstractBehaviorFactory.removePropertiesIfPresent(
0407: tmpProperties, Characteristics.NONE) == false
0408: && componentFactory instanceof BehaviorFactory) {
0409: MutablePicoContainer container = addAdapterInternal(((BehaviorFactory) componentFactory)
0410: .addComponentAdapter(componentMonitor,
0411: lifecycleStrategy, tmpProperties,
0412: componentAdapter));
0413: throwIfPropertiesLeft(tmpProperties);
0414: return container;
0415: } else {
0416: return addAdapterInternal(componentAdapter);
0417: }
0418:
0419: }
0420:
0421: /** {@inheritDoc} **/
0422: public <T> ComponentAdapter<T> removeComponent(
0423: final Object componentKey) {
0424: if (lifecycleState == STARTED) {
0425: throw new PicoCompositionException(
0426: "Cannot remove components after the container has started");
0427: }
0428:
0429: if (lifecycleState == DISPOSED) {
0430: throw new PicoCompositionException(
0431: "Cannot remove components after the container has been disposed");
0432: }
0433:
0434: ComponentAdapter<T> adapter = (ComponentAdapter<T>) getComponentKeyToAdapterCache()
0435: .remove(componentKey);
0436: getModifiableComponentAdapterList().remove(adapter);
0437: getOrderedComponentAdapters().remove(adapter);
0438: return adapter;
0439: }
0440:
0441: /**
0442: * {@inheritDoc}
0443: * The returned ComponentAdapter will be an {@link org.picocontainer.adapters.InstanceAdapter}.
0444: */
0445: public MutablePicoContainer addComponent(final Object implOrInstance) {
0446: return addComponent(implOrInstance, this .componentProperties);
0447: }
0448:
0449: private MutablePicoContainer addComponent(
0450: final Object implOrInstance, final Properties props) {
0451: Class<?> clazz;
0452: if (implOrInstance instanceof String) {
0453: return addComponent(implOrInstance, implOrInstance);
0454: }
0455: if (implOrInstance instanceof Class) {
0456: clazz = (Class<?>) implOrInstance;
0457: } else {
0458: clazz = implOrInstance.getClass();
0459: }
0460: return addComponent(clazz, implOrInstance, props);
0461: }
0462:
0463: public MutablePicoContainer addConfig(final String name,
0464: final Object val) {
0465: return addAdapterInternal(new InstanceAdapter<Object>(name,
0466: val, lifecycleStrategy, componentMonitor));
0467: }
0468:
0469: /**
0470: * {@inheritDoc}
0471: * The returned ComponentAdapter will be instantiated by the {@link ComponentFactory}
0472: * passed to the container's constructor.
0473: */
0474: public MutablePicoContainer addComponent(final Object componentKey,
0475: final Object componentImplementationOrInstance,
0476: final Parameter... parameters) {
0477: return this .addComponent(componentKey,
0478: componentImplementationOrInstance,
0479: this .componentProperties, parameters);
0480: }
0481:
0482: private MutablePicoContainer addComponent(
0483: final Object componentKey,
0484: final Object componentImplementationOrInstance,
0485: final Properties properties, Parameter... parameters) {
0486: if (parameters != null && parameters.length == 0
0487: && parameters != Parameter.ZERO) {
0488: parameters = null; // backwards compatibility! solve this better later - Paul
0489: }
0490: if (componentImplementationOrInstance instanceof Class) {
0491: Properties tmpProperties = (Properties) properties.clone();
0492: ComponentAdapter<?> componentAdapter = componentFactory
0493: .createComponentAdapter(
0494: componentMonitor,
0495: lifecycleStrategy,
0496: tmpProperties,
0497: componentKey,
0498: (Class<?>) componentImplementationOrInstance,
0499: parameters);
0500: throwIfPropertiesLeft(tmpProperties);
0501: return addAdapterInternal(componentAdapter);
0502: } else {
0503: ComponentAdapter<?> componentAdapter = new InstanceAdapter<Object>(
0504: componentKey, componentImplementationOrInstance,
0505: lifecycleStrategy, componentMonitor);
0506: return addAdapter(componentAdapter, properties);
0507: }
0508: }
0509:
0510: private void throwIfPropertiesLeft(final Properties tmpProperties) {
0511: if (tmpProperties.size() > 0) {
0512: throw new PicoCompositionException(
0513: "Unprocessed Characteristics:"
0514: + tmpProperties
0515: + ", refer http://picocontainer.org/unprocessed-properties-help.html");
0516: }
0517: }
0518:
0519: private void addOrderedComponentAdapter(
0520: final ComponentAdapter<?> componentAdapter) {
0521: if (!getOrderedComponentAdapters().contains(componentAdapter)) {
0522: getOrderedComponentAdapters().add(componentAdapter);
0523: }
0524: }
0525:
0526: public List<Object> getComponents() throws PicoException {
0527: return getComponents(Object.class);
0528: }
0529:
0530: public <T> List<T> getComponents(final Class<T> componentType) {
0531: if (componentType == null) {
0532: return Collections.emptyList();
0533: }
0534:
0535: Map<ComponentAdapter<T>, T> adapterToInstanceMap = new HashMap<ComponentAdapter<T>, T>();
0536: for (ComponentAdapter<?> componentAdapter : getModifiableComponentAdapterList()) {
0537: if (componentType.isAssignableFrom(componentAdapter
0538: .getComponentImplementation())) {
0539: ComponentAdapter<T> typedComponentAdapter = typeComponentAdapter(componentAdapter);
0540: T componentInstance = getLocalInstance(typedComponentAdapter);
0541:
0542: adapterToInstanceMap.put(typedComponentAdapter,
0543: componentInstance);
0544: }
0545: }
0546: List<T> result = new ArrayList<T>();
0547: for (ComponentAdapter<?> componentAdapter : getOrderedComponentAdapters()) {
0548: final T componentInstance = adapterToInstanceMap
0549: .get(componentAdapter);
0550: if (componentInstance != null) {
0551: // may be null in the case of the "implicit" addAdapter
0552: // representing "this".
0553: result.add(componentInstance);
0554: }
0555: }
0556: return result;
0557: }
0558:
0559: private <T> T getLocalInstance(
0560: final ComponentAdapter<T> typedComponentAdapter) {
0561: T componentInstance = typedComponentAdapter
0562: .getComponentInstance(this );
0563:
0564: // This is to ensure all are added. (Indirect dependencies will be added
0565: // from InstantiatingComponentAdapter).
0566: addOrderedComponentAdapter(typedComponentAdapter);
0567:
0568: return componentInstance;
0569: }
0570:
0571: @SuppressWarnings({"unchecked"})
0572: private static <T> ComponentAdapter<T> typeComponentAdapter(
0573: final ComponentAdapter<?> componentAdapter) {
0574: return (ComponentAdapter<T>) componentAdapter;
0575: }
0576:
0577: public Object getComponent(final Object componentKeyOrType) {
0578: return getComponent(componentKeyOrType, null);
0579: }
0580:
0581: public Object getComponent(final Object componentKeyOrType,
0582: final Class<? extends Annotation> annotation) {
0583: Object retVal;
0584: if (annotation != null) {
0585: final ComponentAdapter<?> componentAdapter = getComponentAdapter(
0586: (Class<?>) componentKeyOrType, annotation);
0587: retVal = componentAdapter == null ? null
0588: : getInstance(componentAdapter);
0589: } else if (componentKeyOrType instanceof Class) {
0590: final ComponentAdapter<?> componentAdapter = getComponentAdapter(
0591: (Class<?>) componentKeyOrType, (NameBinding) null);
0592: retVal = componentAdapter == null ? null
0593: : getInstance(componentAdapter);
0594: } else {
0595: ComponentAdapter<?> componentAdapter = getComponentAdapter(componentKeyOrType);
0596: retVal = componentAdapter == null ? null
0597: : getInstance(componentAdapter);
0598: }
0599: if (retVal == null) {
0600: retVal = componentMonitor.noComponentFound(this ,
0601: componentKeyOrType);
0602: }
0603: return retVal;
0604: }
0605:
0606: public <T> T getComponent(final Class<T> componentType) {
0607: Object o = getComponent((Object) componentType, null);
0608: return componentType.cast(o);
0609: }
0610:
0611: public <T> T getComponent(final Class<T> componentType,
0612: final Class<? extends Annotation> binding) {
0613: Object o = getComponent((Object) componentType, binding);
0614: return componentType.cast(o);
0615: }
0616:
0617: private Object getInstance(
0618: final ComponentAdapter<?> componentAdapter) {
0619: // check whether this is our adapter
0620: // we need to check this to ensure up-down dependencies cannot be followed
0621: final boolean isLocal = getModifiableComponentAdapterList()
0622: .contains(componentAdapter);
0623:
0624: if (isLocal) {
0625: Object instance;
0626: try {
0627: instance = componentAdapter.getComponentInstance(this );
0628: } catch (AbstractInjector.CyclicDependencyException e) {
0629: if (parent != null) {
0630: instance = parent.getComponent(componentAdapter
0631: .getComponentKey());
0632: if (instance != null) {
0633: return instance;
0634: }
0635: }
0636: throw e;
0637: }
0638: addOrderedComponentAdapter(componentAdapter);
0639:
0640: return instance;
0641: } else if (parent != null) {
0642: return parent.getComponent(componentAdapter
0643: .getComponentKey());
0644: }
0645:
0646: return null;
0647: }
0648:
0649: /** {@inheritDoc} **/
0650: public PicoContainer getParent() {
0651: return parent;
0652: }
0653:
0654: /** {@inheritDoc} **/
0655: public <T> ComponentAdapter<T> removeComponentByInstance(
0656: final T componentInstance) {
0657: for (ComponentAdapter<?> componentAdapter : getModifiableComponentAdapterList()) {
0658: if (getLocalInstance(componentAdapter).equals(
0659: componentInstance)) {
0660: return removeComponent(componentAdapter
0661: .getComponentKey());
0662: }
0663: }
0664: return null;
0665: }
0666:
0667: /**
0668: * Start the components of this PicoContainer and all its logical child containers.
0669: * The starting of the child container is only attempted if the parent
0670: * container start successfully. The child container for which start is attempted
0671: * is tracked so that upon stop, only those need to be stopped.
0672: * The lifecycle operation is delegated to the component adapter,
0673: * if it is an instance of {@link Behavior lifecycle manager}.
0674: * The actual {@link LifecycleStrategy lifecycle strategy} supported
0675: * depends on the concrete implementation of the adapter.
0676: *
0677: * @see Behavior
0678: * @see LifecycleStrategy
0679: * @see #makeChildContainer()
0680: * @see #addChildContainer(PicoContainer)
0681: * @see #removeChildContainer(PicoContainer)
0682: */
0683: public void start() {
0684:
0685: if (!lifecycleState.isStartAllowed()) {
0686: throw new IllegalStateException(
0687: "Cannot start. Current container state was: "
0688: + lifecycleState);
0689: }
0690:
0691: lifecycleState = STARTED;
0692:
0693: startAdapters();
0694: childrenStarted.clear();
0695: for (PicoContainer child : children) {
0696: childrenStarted
0697: .add(new WeakReference<PicoContainer>(child));
0698: if (child instanceof Startable) {
0699: ((Startable) child).start();
0700: }
0701: }
0702: }
0703:
0704: /**
0705: * Stop the components of this PicoContainer and all its logical child containers.
0706: * The stopping of the child containers is only attempted for those that have been
0707: * started, possibly not successfully.
0708: * The lifecycle operation is delegated to the component adapter,
0709: * if it is an instance of {@link Behavior lifecycle manager}.
0710: * The actual {@link LifecycleStrategy lifecycle strategy} supported
0711: * depends on the concrete implementation of the adapter.
0712: *
0713: * @see Behavior
0714: * @see LifecycleStrategy
0715: * @see #makeChildContainer()
0716: * @see #addChildContainer(PicoContainer)
0717: * @see #removeChildContainer(PicoContainer)
0718: */
0719: public void stop() {
0720: if (!lifecycleState.isStopAllowed()) {
0721: throw new IllegalStateException(
0722: "Cannot stop. Current container state was: "
0723: + lifecycleState);
0724: }
0725:
0726: for (PicoContainer child : children) {
0727: if (childStarted(child)) {
0728: if (child instanceof Startable) {
0729: ((Startable) child).stop();
0730: }
0731: }
0732: }
0733: stopAdapters();
0734: lifecycleState = STOPPED;
0735: }
0736:
0737: /**
0738: * Checks the status of the child container to see if it's been started
0739: * to prevent IllegalStateException upon stop
0740: *
0741: * @param child the child PicoContainer
0742: *
0743: * @return A boolean, <code>true</code> if the container is started
0744: */
0745: private boolean childStarted(final PicoContainer child) {
0746: for (WeakReference<PicoContainer> eachChild : childrenStarted) {
0747: PicoContainer ref = eachChild.get();
0748: if (ref == null) {
0749: continue;
0750: }
0751:
0752: if (child.equals(ref)) {
0753: return true;
0754: }
0755: }
0756: return false;
0757: }
0758:
0759: /**
0760: * Dispose the components of this PicoContainer and all its logical child containers.
0761: * The lifecycle operation is delegated to the component adapter,
0762: * if it is an instance of {@link Behavior lifecycle manager}.
0763: * The actual {@link LifecycleStrategy lifecycle strategy} supported
0764: * depends on the concrete implementation of the adapter.
0765: *
0766: * @see Behavior
0767: * @see LifecycleStrategy
0768: * @see #makeChildContainer()
0769: * @see #addChildContainer(PicoContainer)
0770: * @see #removeChildContainer(PicoContainer)
0771: */
0772: public void dispose() {
0773: if (lifecycleState.isStarted()) {
0774: stop();
0775: }
0776:
0777: if (!lifecycleState.isDisposedAllowed()) {
0778: throw new IllegalStateException(
0779: "Cannot dispose. Current lifecycle state is: "
0780: + lifecycleState);
0781: }
0782:
0783: for (PicoContainer child : children) {
0784: if (child instanceof MutablePicoContainer) {
0785: ((Disposable) child).dispose();
0786: }
0787: }
0788: disposeAdapters();
0789: lifecycleState = DISPOSED;
0790: }
0791:
0792: public MutablePicoContainer makeChildContainer() {
0793: DefaultPicoContainer pc = new DefaultPicoContainer(
0794: componentFactory, lifecycleStrategy, this );
0795: addChildContainer(pc);
0796: return pc;
0797: }
0798:
0799: /**
0800: * Checks for identical references in the child container. It doesn't
0801: * traverse an entire hierarchy, namely it simply checks for child containers
0802: * that are equal to the current container.
0803: * @param child
0804: */
0805: private void checkCircularChildDependencies(PicoContainer child) {
0806: final String MESSAGE = "Cannot have circular dependency between parent "
0807: + this + " and child: " + child;
0808: if (child == this ) {
0809: throw new IllegalArgumentException(MESSAGE);
0810: }
0811:
0812: //Todo: Circular Import Dependency on AbstractDelegatingPicoContainer
0813: if (child instanceof AbstractDelegatingPicoContainer) {
0814: AbstractDelegatingPicoContainer delegateChild = (AbstractDelegatingPicoContainer) child;
0815: while (delegateChild != null) {
0816: PicoContainer delegateInstance = delegateChild
0817: .getDelegate();
0818: if (this == delegateInstance) {
0819: throw new IllegalArgumentException(MESSAGE);
0820: }
0821: if (delegateInstance instanceof AbstractDelegatingPicoContainer) {
0822: delegateChild = (AbstractDelegatingPicoContainer) delegateInstance;
0823: } else {
0824: delegateChild = null;
0825: }
0826:
0827: }
0828: }
0829:
0830: }
0831:
0832: public MutablePicoContainer addChildContainer(
0833: final PicoContainer child) {
0834: checkCircularChildDependencies(child);
0835: if (children.add(child)) {
0836: // @todo Should only be added if child container has also be started
0837: if (lifecycleState == STARTED) {
0838: childrenStarted.add(new WeakReference<PicoContainer>(
0839: child));
0840: }
0841: }
0842: return this ;
0843: }
0844:
0845: public boolean removeChildContainer(final PicoContainer child) {
0846: final boolean result = children.remove(child);
0847: WeakReference<PicoContainer> foundRef = null;
0848: for (WeakReference<PicoContainer> eachChild : childrenStarted) {
0849: PicoContainer ref = eachChild.get();
0850: if (ref.equals(child)) {
0851: foundRef = eachChild;
0852: break;
0853: }
0854: }
0855:
0856: if (foundRef != null) {
0857: childrenStarted.remove(foundRef);
0858: }
0859:
0860: return result;
0861: }
0862:
0863: public MutablePicoContainer change(final Properties... properties) {
0864: for (Properties c : properties) {
0865: Enumeration<String> e = (Enumeration<String>) c
0866: .propertyNames();
0867: while (e.hasMoreElements()) {
0868: String s = e.nextElement();
0869: componentProperties.setProperty(s, c.getProperty(s));
0870: }
0871: }
0872: return this ;
0873: }
0874:
0875: public MutablePicoContainer as(final Properties... properties) {
0876: return new AsPropertiesPicoContainer(properties);
0877: }
0878:
0879: public void accept(final PicoVisitor visitor) {
0880: visitor.visitContainer(this );
0881: final List<ComponentAdapter<?>> componentAdapters = new ArrayList<ComponentAdapter<?>>(
0882: getComponentAdapters());
0883: for (ComponentAdapter<?> componentAdapter : componentAdapters) {
0884: componentAdapter.accept(visitor);
0885: }
0886: final List<PicoContainer> allChildren = new ArrayList<PicoContainer>(
0887: children);
0888: for (PicoContainer child : allChildren) {
0889: child.accept(visitor);
0890: }
0891: }
0892:
0893: /**
0894: * Changes monitor in the ComponentFactory, the component adapters
0895: * and the child containers, if these support a ComponentMonitorStrategy.
0896: * {@inheritDoc}
0897: */
0898: public void changeMonitor(final ComponentMonitor monitor) {
0899: this .componentMonitor = monitor;
0900: if (lifecycleStrategy instanceof ComponentMonitorStrategy) {
0901: ((ComponentMonitorStrategy) lifecycleStrategy)
0902: .changeMonitor(monitor);
0903: }
0904: for (ComponentAdapter<?> adapter : getModifiableComponentAdapterList()) {
0905: if (adapter instanceof ComponentMonitorStrategy) {
0906: ((ComponentMonitorStrategy) adapter)
0907: .changeMonitor(monitor);
0908: }
0909: }
0910: for (PicoContainer child : children) {
0911: if (child instanceof ComponentMonitorStrategy) {
0912: ((ComponentMonitorStrategy) child)
0913: .changeMonitor(monitor);
0914: }
0915: }
0916: }
0917:
0918: /**
0919: * Returns the first current monitor found in the ComponentFactory, the component adapters
0920: * and the child containers, if these support a ComponentMonitorStrategy.
0921: * {@inheritDoc}
0922: *
0923: * @throws PicoCompositionException if no component monitor is found in container or its children
0924: */
0925: public ComponentMonitor currentMonitor() {
0926: return componentMonitor;
0927: }
0928:
0929: /**
0930: * {@inheritDoc}
0931: * Loops over all component adapters and invokes
0932: * start(PicoContainer) method on the ones which are LifecycleManagers
0933: */
0934: private void startAdapters() {
0935: Collection<ComponentAdapter<?>> adapters = getComponentAdapters();
0936: for (ComponentAdapter<?> adapter : adapters) {
0937: if (adapter instanceof Behavior) {
0938: Behavior<?> behaviorAdapter = (Behavior<?>) adapter;
0939: if (behaviorAdapter.componentHasLifecycle()) {
0940: // create an instance, it will be added to the ordered CA list
0941: adapter
0942: .getComponentInstance(DefaultPicoContainer.this );
0943: addOrderedComponentAdapter(adapter);
0944: }
0945: }
0946: }
0947: adapters = getOrderedComponentAdapters();
0948: // clear list of started CAs
0949: startedComponentAdapters.clear();
0950: // clone the adapters
0951: List<ComponentAdapter<?>> adaptersClone = new ArrayList<ComponentAdapter<?>>(
0952: adapters);
0953: for (final ComponentAdapter<?> adapter : adaptersClone) {
0954: if (adapter instanceof Behavior) {
0955: Behavior<?> manager = (Behavior<?>) adapter;
0956: manager.start(DefaultPicoContainer.this );
0957: startedComponentAdapters
0958: .add(new WeakReference<ComponentAdapter<?>>(
0959: adapter));
0960: }
0961: }
0962: }
0963:
0964: /**
0965: * {@inheritDoc}
0966: * Loops over started component adapters (in inverse order) and invokes
0967: * stop(PicoContainer) method on the ones which are LifecycleManagers
0968: */
0969: private void stopAdapters() {
0970: for (int i = startedComponentAdapters.size() - 1; 0 <= i; i--) {
0971: ComponentAdapter<?> adapter = startedComponentAdapters.get(
0972: i).get();
0973: if (adapter == null) {
0974: //Weak reference -- may be null
0975: continue;
0976: }
0977: if (adapter instanceof Behavior) {
0978: Behavior<?> manager = (Behavior<?>) adapter;
0979: manager.stop(DefaultPicoContainer.this );
0980: }
0981: }
0982: }
0983:
0984: /**
0985: * {@inheritDoc}
0986: * Loops over all component adapters (in inverse order) and invokes
0987: * dispose(PicoContainer) method on the ones which are LifecycleManagers
0988: */
0989: private void disposeAdapters() {
0990: for (int i = getOrderedComponentAdapters().size() - 1; 0 <= i; i--) {
0991: ComponentAdapter<?> adapter = getOrderedComponentAdapters()
0992: .get(i);
0993: if (adapter instanceof Behavior) {
0994: Behavior<?> manager = (Behavior<?>) adapter;
0995: manager.dispose(DefaultPicoContainer.this );
0996: }
0997: }
0998: }
0999:
1000: /**
1001: * @return the orderedComponentAdapters
1002: */
1003: protected List<ComponentAdapter<?>> getOrderedComponentAdapters() {
1004: return orderedComponentAdapters;
1005: }
1006:
1007: /**
1008: * @return the componentKeyToAdapterCache
1009: */
1010: protected Map<Object, ComponentAdapter<?>> getComponentKeyToAdapterCache() {
1011: return componentKeyToAdapterCache;
1012: }
1013:
1014: /**
1015: * @return the componentAdapters
1016: */
1017: protected List<ComponentAdapter<?>> getModifiableComponentAdapterList() {
1018: return componentAdapters;
1019: }
1020:
1021: private class AsPropertiesPicoContainer extends
1022: AbstractDelegatingMutablePicoContainer {
1023: /**
1024: * Serialization UUID.
1025: */
1026: private static final long serialVersionUID = -4846748925372564136L;
1027:
1028: private final Properties properties;
1029:
1030: public AsPropertiesPicoContainer(final Properties... props) {
1031: super (DefaultPicoContainer.this );
1032: properties = (Properties) componentProperties.clone();
1033: for (Properties c : props) {
1034: Enumeration<?> e = c.propertyNames();
1035: while (e.hasMoreElements()) {
1036: String s = (String) e.nextElement();
1037: properties.setProperty(s, c.getProperty(s));
1038: }
1039: }
1040: }
1041:
1042: @Override
1043: public MutablePicoContainer makeChildContainer() {
1044: return getDelegate().makeChildContainer();
1045: }
1046:
1047: @Override
1048: public MutablePicoContainer addComponent(
1049: final Object componentKey,
1050: final Object componentImplementationOrInstance,
1051: final Parameter... parameters)
1052: throws PicoCompositionException {
1053: return DefaultPicoContainer.this .addComponent(componentKey,
1054: componentImplementationOrInstance, properties,
1055: parameters);
1056: }
1057:
1058: @Override
1059: public MutablePicoContainer addComponent(
1060: final Object implOrInstance)
1061: throws PicoCompositionException {
1062: return DefaultPicoContainer.this .addComponent(
1063: implOrInstance, properties);
1064: }
1065:
1066: @Override
1067: public MutablePicoContainer addAdapter(
1068: final ComponentAdapter<?> componentAdapter)
1069: throws PicoCompositionException {
1070: return DefaultPicoContainer.this.addAdapter(
1071: componentAdapter, properties);
1072: }
1073: }
1074:
1075: }
|