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.defaults;
011    
012    import java.io.Serializable;
013    import java.util.ArrayList;
014    import java.util.Collection;
015    import java.util.Collections;
016    import java.util.HashMap;
017    import java.util.HashSet;
018    import java.util.Iterator;
019    import java.util.List;
020    import java.util.Map;
021    import java.util.Set;
022    
023    import org.picocontainer.ComponentAdapter;
024    import org.picocontainer.ComponentMonitor;
025    import org.picocontainer.LifecycleManager;
026    import org.picocontainer.MutablePicoContainer;
027    import org.picocontainer.Parameter;
028    import org.picocontainer.PicoContainer;
029    import org.picocontainer.PicoException;
030    import org.picocontainer.PicoIntrospectionException;
031    import org.picocontainer.PicoVerificationException;
032    import org.picocontainer.PicoVisitor;
033    import org.picocontainer.monitors.DefaultComponentMonitor;
034    
035    /**
036     * <p/>
037     * The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation.
038     * Constructing a container c with a parent p container will cause c to look up components
039     * in p if they cannot be found inside c itself.
040     * </p>
041     * <p/>
042     * Using {@link Class} objects as keys to the various registerXXX() methods makes
043     * a subtle semantic difference:
044     * </p>
045     * <p/>
046     * If there are more than one registered components of the same type and one of them are
047     * registered with a {@link java.lang.Class} key of the corresponding type, this component
048     * will take precedence over other components during type resolution.
049     * </p>
050     * <p/>
051     * Another place where keys that are classes make a subtle difference is in
052     * {@link org.picocontainer.defaults.ImplementationHidingComponentAdapter}.
053     * </p>
054     * <p/>
055     * This implementation of {@link MutablePicoContainer} also supports
056     * {@link ComponentMonitorStrategy}.
057     * </p>
058     *
059     * @author Paul Hammant
060     * @author Aslak Helles&oslash;y
061     * @author Jon Tirs&eacute;n
062     * @author Thomas Heller
063     * @author Mauro Talevi
064     * @version $Revision: 1.8 $
065     */
066    public class DefaultPicoContainer implements MutablePicoContainer, ComponentMonitorStrategy, Serializable {
067        private Map componentKeyToAdapterCache = new HashMap();
068        private ComponentAdapterFactory componentAdapterFactory;
069        private PicoContainer parent;
070        private Set children = new HashSet();
071    
072        private List componentAdapters = new ArrayList();
073        // Keeps track of instantiation order.
074        private List orderedComponentAdapters = new ArrayList();
075    
076        // Keeps track of the container started status
077        private boolean started = false;
078        // Keeps track of the container disposed status
079        private boolean disposed = false;
080        // Keeps track of child containers started status
081        private Set childrenStarted = new HashSet();
082    
083        private LifecycleManager lifecycleManager = new OrderedComponentAdapterLifecycleManager();
084        private LifecycleStrategy lifecycleStrategyForInstanceRegistrations;
085    
086        /**
087         * Creates a new container with a custom ComponentAdapterFactory and a parent container.
088         * <p/>
089         * <em>
090         * Important note about caching: If you intend the components to be cached, you should pass
091         * in a factory that creates {@link CachingComponentAdapter} instances, such as for example
092         * {@link CachingComponentAdapterFactory}. CachingComponentAdapterFactory can delegate to
093         * other ComponentAdapterFactories.
094         * </em>
095         *
096         * @param componentAdapterFactory the factory to use for creation of ComponentAdapters.
097         * @param parent                  the parent container (used for component dependency lookups).
098         */
099        public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent) {
100            this(componentAdapterFactory, new DefaultLifecycleStrategy(new DefaultComponentMonitor()), parent);
101        }
102    
103        /**
104         * Creates a new container with a custom ComponentAdapterFactory, LifecycleStrategy for instance registration,
105         *  and a parent container.
106         * <p/>
107         * <em>
108         * Important note about caching: If you intend the components to be cached, you should pass
109         * in a factory that creates {@link CachingComponentAdapter} instances, such as for example
110         * {@link CachingComponentAdapterFactory}. CachingComponentAdapterFactory can delegate to
111         * other ComponentAdapterFactories.
112         * </em>
113         *
114         * @param componentAdapterFactory the factory to use for creation of ComponentAdapters.
115         * @param lifecycleStrategyForInstanceRegistrations the lifecylce strategy chosen for regiered
116         *          instance (not implementations!)
117         * @param parent                  the parent container (used for component dependency lookups).
118         */
119        public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory,
120                                    LifecycleStrategy lifecycleStrategyForInstanceRegistrations,
121                                    PicoContainer parent) {
122            if (componentAdapterFactory == null) throw new NullPointerException("componentAdapterFactory");
123            if (lifecycleStrategyForInstanceRegistrations == null) throw new NullPointerException("lifecycleStrategyForInstanceRegistrations");
124            this.componentAdapterFactory = componentAdapterFactory;
125            this.lifecycleStrategyForInstanceRegistrations = lifecycleStrategyForInstanceRegistrations;
126            this.parent = parent == null ? null : ImmutablePicoContainerProxyFactory.newProxyInstance(parent);
127        }
128    
129        /**
130          * Creates a new container with the DefaultComponentAdapterFactory using a
131          * custom ComponentMonitor
132          *
133          * @param monitor the ComponentMonitor to use
134          * @param parent the parent container (used for component dependency lookups).
135          */
136        public DefaultPicoContainer(ComponentMonitor monitor, PicoContainer parent) {
137            this(new DefaultComponentAdapterFactory(monitor), parent);
138            lifecycleStrategyForInstanceRegistrations = new DefaultLifecycleStrategy(monitor);
139        }
140    
141        /**
142          * Creates a new container with the DefaultComponentAdapterFactory using a
143          * custom ComponentMonitor and lifecycle strategy
144          *
145          * @param monitor the ComponentMonitor to use
146          * @param lifecycleStrategy the lifecycle strategy to use.
147          * @param parent the parent container (used for component dependency lookups).
148          */
149        public DefaultPicoContainer(ComponentMonitor monitor, LifecycleStrategy lifecycleStrategy, PicoContainer parent) {
150            this(new DefaultComponentAdapterFactory(monitor, lifecycleStrategy), lifecycleStrategy,  parent);
151        }
152    
153        /**
154          * Creates a new container with the DefaultComponentAdapterFactory using a
155          * custom lifecycle strategy
156          *
157          * @param lifecycleStrategy the lifecycle strategy to use.
158          * @param parent the parent container (used for component dependency lookups).
159          */
160        public DefaultPicoContainer(LifecycleStrategy lifecycleStrategy, PicoContainer parent) {
161            this(new DefaultComponentMonitor(), lifecycleStrategy, parent);
162        }
163    
164    
165        /**
166         * Creates a new container with a custom ComponentAdapterFactory and no parent container.
167         *
168         * @param componentAdapterFactory the ComponentAdapterFactory to use.
169         */
170        public DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory) {
171            this(componentAdapterFactory, null);
172        }
173    
174        /**
175          * Creates a new container with the DefaultComponentAdapterFactory using a
176          * custom ComponentMonitor
177          *
178          * @param monitor the ComponentMonitor to use
179          */
180        public DefaultPicoContainer(ComponentMonitor monitor) {
181            this(monitor, new DefaultLifecycleStrategy(monitor), null);
182        }
183    
184        /**
185         * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory}
186         * and a parent container.
187         *
188         * @param parent the parent container (used for component dependency lookups).
189         */
190        public DefaultPicoContainer(PicoContainer parent) {
191            this(new DefaultComponentAdapterFactory(), parent);
192        }
193    
194        /**
195         * Creates a new container with a (caching) {@link DefaultComponentAdapterFactory} and no parent container.
196         */
197        public DefaultPicoContainer() {
198            this(new DefaultComponentAdapterFactory(), null);
199        }
200    
201        public Collection getComponentAdapters() {
202            return Collections.unmodifiableList(componentAdapters);
203        }
204    
205        public final ComponentAdapter getComponentAdapter(Object componentKey) {
206            ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.get(componentKey);
207            if (adapter == null && parent != null) {
208                adapter = parent.getComponentAdapter(componentKey);
209            }
210            return adapter;
211        }
212    
213        public ComponentAdapter getComponentAdapterOfType(Class componentType) {
214            // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
215            ComponentAdapter adapterByKey = getComponentAdapter(componentType);
216            if (adapterByKey != null) {
217                return adapterByKey;
218            }
219    
220            List found = getComponentAdaptersOfType(componentType);
221    
222            if (found.size() == 1) {
223                return ((ComponentAdapter) found.get(0));
224            } else if (found.size() == 0) {
225                if (parent != null) {
226                    return parent.getComponentAdapterOfType(componentType);
227                } else {
228                    return null;
229                }
230            } else {
231                Class[] foundClasses = new Class[found.size()];
232                for (int i = 0; i < foundClasses.length; i++) {
233                    foundClasses[i] = ((ComponentAdapter) found.get(i)).getComponentImplementation();
234                }
235    
236                throw new AmbiguousComponentResolutionException(componentType, foundClasses);
237            }
238        }
239    
240        public List getComponentAdaptersOfType(Class componentType) {
241            if (componentType == null) {
242                return Collections.EMPTY_LIST;
243            }
244            List found = new ArrayList();
245            for (Iterator iterator = getComponentAdapters().iterator(); iterator.hasNext();) {
246                ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
247    
248                if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
249                    found.add(componentAdapter);
250                }
251            }
252            return found;
253        }
254    
255        /**
256         * {@inheritDoc}
257         * This method can be used to override the ComponentAdapter created by the {@link ComponentAdapterFactory}
258         * passed to the constructor of this container.
259         */
260        public ComponentAdapter registerComponent(ComponentAdapter componentAdapter) {
261            Object componentKey = componentAdapter.getComponentKey();
262            if (componentKeyToAdapterCache.containsKey(componentKey)) {
263                throw new DuplicateComponentKeyRegistrationException(componentKey);
264            }
265            componentAdapters.add(componentAdapter);
266            componentKeyToAdapterCache.put(componentKey, componentAdapter);
267            return componentAdapter;
268        }
269    
270        public ComponentAdapter unregisterComponent(Object componentKey) {
271            ComponentAdapter adapter = (ComponentAdapter) componentKeyToAdapterCache.remove(componentKey);
272            componentAdapters.remove(adapter);
273            orderedComponentAdapters.remove(adapter);
274            return adapter;
275        }
276    
277        /**
278         * {@inheritDoc}
279         * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
280         */
281        public ComponentAdapter registerComponentInstance(Object component) {
282            return registerComponentInstance(component.getClass(), component);
283        }
284    
285        /**
286         * {@inheritDoc}
287         * The returned ComponentAdapter will be an {@link InstanceComponentAdapter}.
288         */
289        public ComponentAdapter registerComponentInstance(Object componentKey, Object componentInstance) {
290            ComponentAdapter componentAdapter = new InstanceComponentAdapter(componentKey, componentInstance, lifecycleStrategyForInstanceRegistrations);
291            return registerComponent(componentAdapter);
292        }
293    
294        /**
295         * {@inheritDoc}
296         * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
297         * passed to the container's constructor.
298         */
299        public ComponentAdapter registerComponentImplementation(Class componentImplementation) {
300            return registerComponentImplementation(componentImplementation, componentImplementation);
301        }
302    
303        /**
304         * {@inheritDoc}
305         * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
306         * passed to the container's constructor.
307         */
308        public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation) {
309            return registerComponentImplementation(componentKey, componentImplementation, (Parameter[]) null);
310        }
311    
312        /**
313         * {@inheritDoc}
314         * The returned ComponentAdapter will be instantiated by the {@link ComponentAdapterFactory}
315         * passed to the container's constructor.
316         */
317        public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, Parameter[] parameters) {
318            ComponentAdapter componentAdapter = componentAdapterFactory.createComponentAdapter(componentKey, componentImplementation, parameters);
319            return registerComponent(componentAdapter);
320        }
321    
322        /**
323         * Same as {@link #registerComponentImplementation(java.lang.Object, java.lang.Class, org.picocontainer.Parameter[])}
324         * but with parameters as a {@link List}. Makes it possible to use with Groovy arrays (which are actually Lists).
325         */
326        public ComponentAdapter registerComponentImplementation(Object componentKey, Class componentImplementation, List parameters) {
327            Parameter[] parametersAsArray = (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
328            return registerComponentImplementation(componentKey, componentImplementation, parametersAsArray);
329        }
330    
331        private void addOrderedComponentAdapter(ComponentAdapter componentAdapter) {
332            if (!orderedComponentAdapters.contains(componentAdapter)) {
333                orderedComponentAdapters.add(componentAdapter);
334            }
335        }
336    
337        public List getComponentInstances() throws PicoException {
338            return getComponentInstancesOfType(Object.class);
339        }
340    
341        public List getComponentInstancesOfType(Class componentType) {
342            if (componentType == null) {
343                return Collections.EMPTY_LIST;
344            }
345    
346            Map adapterToInstanceMap = new HashMap();
347            for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
348                ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
349                if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
350                    Object componentInstance = getInstance(componentAdapter);
351                    adapterToInstanceMap.put(componentAdapter, componentInstance);
352    
353                    // This is to ensure all are added. (Indirect dependencies will be added
354                    // from InstantiatingComponentAdapter).
355                    addOrderedComponentAdapter(componentAdapter);
356                }
357            }
358            List result = new ArrayList();
359            for (Iterator iterator = orderedComponentAdapters.iterator(); iterator.hasNext();) {
360                Object componentAdapter = iterator.next();
361                final Object componentInstance = adapterToInstanceMap.get(componentAdapter);
362                if (componentInstance != null) {
363                    // may be null in the case of the "implicit" adapter
364                    // representing "this".
365                    result.add(componentInstance);
366                }
367            }
368            return result;
369        }
370    
371        public Object getComponentInstance(Object componentKey) {
372            ComponentAdapter componentAdapter = getComponentAdapter(componentKey);
373            if (componentAdapter != null) {
374                return getInstance(componentAdapter);
375            } else {
376                return null;
377            }
378        }
379    
380        public Object getComponentInstanceOfType(Class componentType) {
381            final ComponentAdapter componentAdapter = getComponentAdapterOfType(componentType);
382            return componentAdapter == null ? null : getInstance(componentAdapter);
383        }
384    
385        private Object getInstance(ComponentAdapter componentAdapter) {
386            // check wether this is our adapter
387            // we need to check this to ensure up-down dependencies cannot be followed
388            final boolean isLocal = componentAdapters.contains(componentAdapter);
389    
390            if (isLocal) {
391                Object instance = null;
392                try {
393                    instance = componentAdapter.getComponentInstance(this);
394                } catch (CyclicDependencyException e) {
395                    if (parent != null) {
396                        instance = parent.getComponentInstance(componentAdapter.getComponentKey());
397                        if( instance != null ) {
398                            return instance;
399                        }
400                    }
401                    throw e;
402                }
403                addOrderedComponentAdapter(componentAdapter);
404    
405                return instance;
406            } else if (parent != null) {
407                return parent.getComponentInstance(componentAdapter.getComponentKey());
408            }
409    
410            return null;
411        }
412    
413    
414        public PicoContainer getParent() {
415            return parent;
416        }
417    
418        public ComponentAdapter unregisterComponentByInstance(Object componentInstance) {
419            Collection componentAdapters = getComponentAdapters();
420            for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
421                ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
422                if (getInstance(componentAdapter).equals(componentInstance)) {
423                    return unregisterComponent(componentAdapter.getComponentKey());
424                }
425            }
426            return null;
427        }
428    
429        /**
430         * @deprecated since 1.1 - Use "new VerifyingVisitor().traverse(this)"
431         */
432        public void verify() throws PicoVerificationException {
433            new VerifyingVisitor().traverse(this);
434        }
435    
436        /**
437         * Start the components of this PicoContainer and all its logical child containers.
438         * The starting of the child container is only attempted if the parent
439         * container start successfully.  The child container for which start is attempted
440         * is tracked so that upon stop, only those need to be stopped.
441         * The lifecycle operation is delegated to the component adapter,
442         * if it is an instance of {@link LifecycleManager lifecycle manager}.
443         * The actual {@link LifecycleStrategy lifecycle strategy} supported
444         * depends on the concrete implementation of the adapter.
445         *
446         * @see LifecycleManager
447         * @see LifecycleStrategy
448         * @see #makeChildContainer()
449         * @see #addChildContainer(PicoContainer)
450         * @see #removeChildContainer(PicoContainer)
451         */
452        public void start() {
453            if (disposed) throw new IllegalStateException("Already disposed");
454            if (started) throw new IllegalStateException("Already started");
455            started = true;
456            this.lifecycleManager.start(this);
457            childrenStarted.clear();
458            for (Iterator iterator = children.iterator(); iterator.hasNext();) {
459                PicoContainer child = (PicoContainer) iterator.next();
460                childrenStarted.add(new Integer(child.hashCode()));
461                child.start();
462            }
463        }
464    
465        /**
466         * Stop the components of this PicoContainer and all its logical child containers.
467         * The stopping of the child containers is only attempted for those that have been
468         * started, possibly not successfully.
469         * The lifecycle operation is delegated to the component adapter,
470         * if it is an instance of {@link LifecycleManager lifecycle manager}.
471         * The actual {@link LifecycleStrategy lifecycle strategy} supported
472         * depends on the concrete implementation of the adapter.
473         *
474         * @see LifecycleManager
475         * @see LifecycleStrategy
476         * @see #makeChildContainer()
477         * @see #addChildContainer(PicoContainer)
478         * @see #removeChildContainer(PicoContainer)
479         */
480        public void stop() {
481            if (disposed) throw new IllegalStateException("Already disposed");
482            if (!started) throw new IllegalStateException("Not started");
483            for (Iterator iterator = children.iterator(); iterator.hasNext();) {
484                PicoContainer child = (PicoContainer) iterator.next();
485                if ( childStarted(child) ){
486                    child.stop();
487                }
488            }
489            this.lifecycleManager.stop(this);
490            started = false;
491        }
492    
493        /**
494         * Checks the status of the child container to see if it's been started
495         * to prevent IllegalStateException upon stop
496         * @param child the child PicoContainer
497         * @return A boolean, <code>true</code> if the container is started
498         */
499        private boolean childStarted(PicoContainer child) {
500            return childrenStarted.contains(new Integer(child.hashCode()));
501        }
502    
503        /**
504         * Dispose the components of this PicoContainer and all its logical child containers.
505         * The lifecycle operation is delegated to the component adapter,
506         * if it is an instance of {@link LifecycleManager lifecycle manager}.
507         * The actual {@link LifecycleStrategy lifecycle strategy} supported
508         * depends on the concrete implementation of the adapter.
509         *
510         * @see LifecycleManager
511         * @see LifecycleStrategy
512         * @see #makeChildContainer()
513         * @see #addChildContainer(PicoContainer)
514         * @see #removeChildContainer(PicoContainer)
515         */
516        public void dispose() {
517            if (disposed) throw new IllegalStateException("Already disposed");
518            for (Iterator iterator = children.iterator(); iterator.hasNext();) {
519                PicoContainer child = (PicoContainer) iterator.next();
520                child.dispose();
521            }
522            this.lifecycleManager.dispose(this);
523            disposed = true;
524        }
525    
526        public MutablePicoContainer makeChildContainer() {
527            DefaultPicoContainer pc = new DefaultPicoContainer(componentAdapterFactory,
528                                                               lifecycleStrategyForInstanceRegistrations,
529                                                               this);
530            addChildContainer(pc);
531            return pc;
532        }
533    
534        public boolean addChildContainer(PicoContainer child) {
535            if (children.add(child)) {
536                // @todo Should only be added if child container has also be started
537                if (started) {
538                    childrenStarted.add(new Integer(child.hashCode()));
539                }
540                return true;
541            } else {
542                return false;
543            }
544        }
545    
546        public boolean removeChildContainer(PicoContainer child) {
547            final boolean result = children.remove(child);
548            childrenStarted.remove(new Integer(child.hashCode()));
549            return result;
550        }
551    
552        public void accept(PicoVisitor visitor) {
553            visitor.visitContainer(this);
554            final List componentAdapters = new ArrayList(getComponentAdapters());
555            for (Iterator iterator = componentAdapters.iterator(); iterator.hasNext();) {
556                ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
557                componentAdapter.accept(visitor);
558            }
559            final List allChildren = new ArrayList(children);
560            for (Iterator iterator = allChildren.iterator(); iterator.hasNext();) {
561                PicoContainer child = (PicoContainer) iterator.next();
562                child.accept(visitor);
563            }
564        }
565    
566        /**
567         * Changes monitor in the ComponentAdapterFactory, the component adapters
568         * and the child containers, if these support a ComponentMonitorStrategy.
569         * {@inheritDoc}
570         */
571        public void changeMonitor(ComponentMonitor monitor) {
572            // will also change monitor in lifecycleStrategyForInstanceRegistrations
573            if (componentAdapterFactory instanceof ComponentMonitorStrategy) {
574                ((ComponentMonitorStrategy) componentAdapterFactory).changeMonitor(monitor);
575            }
576            for ( Iterator i = componentAdapters.iterator(); i.hasNext(); ){
577                Object adapter = i.next();
578                if ( adapter instanceof ComponentMonitorStrategy ) {
579                    ((ComponentMonitorStrategy)adapter).changeMonitor(monitor);
580                }
581            }
582            for (Iterator i = children.iterator(); i.hasNext();) {
583                Object child = i.next();
584                if (child instanceof ComponentMonitorStrategy) {
585                    ((ComponentMonitorStrategy) child).changeMonitor(monitor);
586                }
587            }
588        }
589    
590        /**
591         * Returns the first current monitor found in the ComponentAdapterFactory, the component adapters
592         * and the child containers, if these support a ComponentMonitorStrategy.
593         * {@inheritDoc}
594         * @throws PicoIntrospectionException if no component monitor is found in container or its children
595         */
596        public ComponentMonitor currentMonitor() {
597            if (componentAdapterFactory instanceof ComponentMonitorStrategy) {
598                return ((ComponentMonitorStrategy) componentAdapterFactory).currentMonitor();
599            }
600            for ( Iterator i = componentAdapters.iterator(); i.hasNext(); ){
601                Object adapter = i.next();
602                if ( adapter instanceof ComponentMonitorStrategy ) {
603                    return ((ComponentMonitorStrategy)adapter).currentMonitor();
604                }
605            }
606            for (Iterator i = children.iterator(); i.hasNext();) {
607                Object child = i.next();
608                if (child instanceof ComponentMonitorStrategy) {
609                    return ((ComponentMonitorStrategy) child).currentMonitor();
610                }
611            }
612            throw new PicoIntrospectionException("No component monitor found in container or its children");
613        }
614    
615       /**
616        * <p>
617        * Implementation of lifecycle manager which delegates to the container's component adapters.
618        * The component adapters will be ordered by dependency as registered in the container.
619        * This LifecycleManager will delegate calls on the lifecycle methods to the component adapters
620        * if these are themselves LifecycleManagers.
621        * </p>
622        *
623        * @author Mauro Talevi
624        * @since 1.2
625        */
626        private class OrderedComponentAdapterLifecycleManager implements LifecycleManager, Serializable {
627    
628            /** List collecting the CAs which have been successfully started */
629            private List startedComponentAdapters = new ArrayList();
630    
631            /**
632             * {@inheritDoc}
633             * Loops over all component adapters and invokes
634             * start(PicoContainer) method on the ones which are LifecycleManagers
635             */
636            public void start(PicoContainer node) {
637                Collection adapters = getComponentAdapters();
638                for (final Iterator iter = adapters.iterator(); iter.hasNext();) {
639                    final ComponentAdapter adapter = (ComponentAdapter)iter.next();
640                    if ( adapter instanceof LifecycleManager ){
641                        LifecycleManager manager = (LifecycleManager)adapter;
642                        if (manager.hasLifecycle()) {
643                            // create an instance, it will be added to the ordered CA list
644                            adapter.getComponentInstance(node);
645                            addOrderedComponentAdapter(adapter);
646                        }
647                    }
648                }
649                adapters = orderedComponentAdapters;
650                // clear list of started CAs
651                startedComponentAdapters.clear();
652                for (final Iterator iter = adapters.iterator(); iter.hasNext();) {
653                    final Object adapter = iter.next();
654                    if ( adapter instanceof LifecycleManager ){
655                        LifecycleManager manager = (LifecycleManager)adapter;
656                        manager.start(node);
657                        startedComponentAdapters.add(adapter);
658                    }
659                }
660            }
661    
662            /**
663             * {@inheritDoc}
664             * Loops over started component adapters (in inverse order) and invokes
665             * stop(PicoContainer) method on the ones which are LifecycleManagers
666             */
667            public void stop(PicoContainer node) {
668                List adapters = startedComponentAdapters;
669                for (int i = adapters.size() - 1; 0 <= i; i--) {
670                    Object adapter = adapters.get(i);
671                    if ( adapter instanceof LifecycleManager ){
672                        LifecycleManager manager = (LifecycleManager)adapter;
673                        manager.stop(node);
674                    }
675                }
676            }
677    
678            /**
679             * {@inheritDoc}
680             * Loops over all component adapters (in inverse order) and invokes
681             * dispose(PicoContainer) method on the ones which are LifecycleManagers
682             */
683            public void dispose(PicoContainer node) {
684                List adapters = orderedComponentAdapters;
685                for (int i = adapters.size() - 1; 0 <= i; i--) {
686                    Object adapter = adapters.get(i);
687                    if ( adapter instanceof LifecycleManager ){
688                        LifecycleManager manager = (LifecycleManager)adapter;
689                        manager.dispose(node);
690                    }
691                }
692            }
693    
694            public boolean hasLifecycle() {
695                throw new UnsupportedOperationException("Should not have been called");
696            }
697    
698        }
699    
700    }