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