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.InstanceAdapter;
013 import org.picocontainer.behaviors.Cached;
014 import org.picocontainer.behaviors.Caching;
015 import org.picocontainer.behaviors.HiddenImplementation;
016 import org.picocontainer.behaviors.AdaptiveBehavior;
017 import org.picocontainer.behaviors.AbstractBehaviorFactory;
018 import org.picocontainer.containers.AbstractDelegatingMutablePicoContainer;
019 import org.picocontainer.containers.EmptyPicoContainer;
020 import org.picocontainer.containers.ImmutablePicoContainer;
021 import org.picocontainer.injectors.AbstractInjector;
022 import org.picocontainer.injectors.AdaptiveInjection;
023 import org.picocontainer.lifecycle.StartableLifecycleStrategy;
024 import org.picocontainer.monitors.NullComponentMonitor;
025
026 import java.io.Serializable;
027 import java.util.ArrayList;
028 import java.util.Collections;
029 import java.util.HashMap;
030 import java.util.HashSet;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.Set;
034 import java.util.Properties;
035 import java.util.Enumeration;
036 import java.util.Collection;
037
038 /**
039 * <p/>
040 * The Standard {@link PicoContainer}/{@link MutablePicoContainer} implementation.
041 * Constructing a container c with a parent p container will cause c to look up components
042 * in p if they cannot be found inside c itself.
043 * </p>
044 * <p/>
045 * Using {@link Class} objects as keys to the various registerXXX() methods makes
046 * a subtle semantic difference:
047 * </p>
048 * <p/>
049 * If there are more than one registered components of the same type and one of them are
050 * registered with a {@link java.lang.Class} key of the corresponding type, this addComponent
051 * will take precedence over other components during type resolution.
052 * </p>
053 * <p/>
054 * Another place where keys that are classes make a subtle difference is in
055 * {@link HiddenImplementation}.
056 * </p>
057 * <p/>
058 * This implementation of {@link MutablePicoContainer} also supports
059 * {@link ComponentMonitorStrategy}.
060 * </p>
061 *
062 * @author Paul Hammant
063 * @author Aslak Hellesøy
064 * @author Jon Tirsén
065 * @author Thomas Heller
066 * @author Mauro Talevi
067 */
068 public class DefaultPicoContainer implements MutablePicoContainer, ComponentMonitorStrategy, Serializable {
069
070 private final Map<Object, ComponentAdapter> componentKeyToAdapterCache = new HashMap<Object, ComponentAdapter>();
071 private final List<ComponentAdapter<?>> componentAdapters = new ArrayList<ComponentAdapter<?>>();
072 // Keeps track of instantiation order.
073 private final List<ComponentAdapter<?>> orderedComponentAdapters = new ArrayList<ComponentAdapter<?>>();
074
075
076 private ComponentFactory componentFactory;
077 private PicoContainer parent;
078 private final Set<PicoContainer> children = new HashSet<PicoContainer>();
079
080 // Keeps track of the container started status
081 private boolean started = false;
082 // Keeps track of the container disposed status
083 private boolean disposed = false;
084 // Keeps track of child containers started status
085 private final Set<Integer> childrenStarted = new HashSet<Integer>();
086
087 private LifecycleStrategy lifecycleStrategy;
088 private final Properties componentProperties = new Properties();
089 private ComponentMonitor componentMonitor;
090
091 /** List collecting the CAs which have been successfully started */
092 private final List<Integer> startedComponentAdapters = new ArrayList<Integer>();
093
094 /**
095 * Creates a new container with a custom ComponentFactory and a parent container.
096 * <p/>
097 * <em>
098 * Important note about caching: If you intend the components to be cached, you should pass
099 * in a factory that creates {@link Cached} instances, such as for example
100 * {@link Caching}. Caching can delegate to
101 * other ComponentAdapterFactories.
102 * </em>
103 *
104 * @param componentFactory the factory to use for creation of ComponentAdapters.
105 * @param parent the parent container (used for component dependency lookups).
106 */
107 public DefaultPicoContainer(ComponentFactory componentFactory, PicoContainer parent) {
108 this(componentFactory, new StartableLifecycleStrategy(new NullComponentMonitor()), parent, new NullComponentMonitor());
109 }
110
111 /**
112 * Creates a new container with a custom ComponentFactory, LifecycleStrategy for instance registration,
113 * and a parent container.
114 * <p/>
115 * <em>
116 * Important note about caching: If you intend the components to be cached, you should pass
117 * in a factory that creates {@link Cached} instances, such as for example
118 * {@link Caching}. Caching can delegate to
119 * other ComponentAdapterFactories.
120 * </em>
121 *
122 * @param componentFactory the factory to use for creation of ComponentAdapters.
123 * @param lifecycleStrategy
124 * the lifecylce strategy chosen for regiered
125 * instance (not implementations!)
126 * @param parent the parent container (used for component dependency lookups).
127 */
128 public DefaultPicoContainer(ComponentFactory componentFactory,
129 LifecycleStrategy lifecycleStrategy,
130 PicoContainer parent) {
131 this(componentFactory, lifecycleStrategy, parent, new NullComponentMonitor() );
132 }
133
134 public DefaultPicoContainer(ComponentFactory componentFactory,
135 LifecycleStrategy lifecycleStrategy,
136 PicoContainer parent, ComponentMonitor componentMonitor) {
137 if (componentFactory == null) throw new NullPointerException("componentFactory");
138 if (lifecycleStrategy == null) throw new NullPointerException("lifecycleStrategy");
139 this.componentFactory = componentFactory;
140 this.lifecycleStrategy = lifecycleStrategy;
141 this.parent = parent;
142 if (parent != null && !(parent instanceof EmptyPicoContainer)) {
143 this.parent = new ImmutablePicoContainer(parent);
144 }
145 this.componentMonitor = componentMonitor;
146 }
147
148 /**
149 * Creates a new container with the AdaptiveInjection using a
150 * custom ComponentMonitor
151 *
152 * @param monitor the ComponentMonitor to use
153 * @param parent the parent container (used for component dependency lookups).
154 */
155 public DefaultPicoContainer(ComponentMonitor monitor, PicoContainer parent) {
156 this(new AdaptiveBehavior(), new StartableLifecycleStrategy(monitor), parent, monitor);
157 }
158
159 /**
160 * Creates a new container with the AdaptiveInjection using a
161 * custom ComponentMonitor and lifecycle strategy
162 *
163 * @param monitor the ComponentMonitor to use
164 * @param lifecycleStrategy the lifecycle strategy to use.
165 * @param parent the parent container (used for component dependency lookups).
166 */
167 public DefaultPicoContainer(ComponentMonitor monitor, LifecycleStrategy lifecycleStrategy, PicoContainer parent) {
168 this(new AdaptiveBehavior(), lifecycleStrategy, parent, monitor);
169 }
170
171 /**
172 * Creates a new container with the AdaptiveInjection using a
173 * custom lifecycle strategy
174 *
175 * @param lifecycleStrategy the lifecycle strategy to use.
176 * @param parent the parent container (used for component dependency lookups).
177 */
178 public DefaultPicoContainer(LifecycleStrategy lifecycleStrategy, PicoContainer parent) {
179 this(new NullComponentMonitor(), lifecycleStrategy, parent);
180 }
181
182
183 /**
184 * Creates a new container with a custom ComponentFactory and no parent container.
185 *
186 * @param componentFactory the ComponentFactory to use.
187 */
188 public DefaultPicoContainer(ComponentFactory componentFactory) {
189 this(componentFactory, null);
190 }
191
192 /**
193 * Creates a new container with the AdaptiveInjection using a
194 * custom ComponentMonitor
195 *
196 * @param monitor the ComponentMonitor to use
197 */
198 public DefaultPicoContainer(ComponentMonitor monitor) {
199 this(monitor, new StartableLifecycleStrategy(monitor), null);
200 }
201
202 /**
203 * Creates a new container with a (caching) {@link AdaptiveInjection}
204 * and a parent container.
205 *
206 * @param parent the parent container (used for component dependency lookups).
207 */
208 public DefaultPicoContainer(PicoContainer parent) {
209 this(new AdaptiveBehavior(), parent);
210 }
211
212 /** Creates a new container with a {@link AdaptiveBehavior} and no parent container. */
213 public DefaultPicoContainer() {
214 this(new AdaptiveBehavior(), null);
215 }
216
217 public Collection<ComponentAdapter<?>> getComponentAdapters() {
218 return Collections.unmodifiableList(componentAdapters);
219 }
220
221 public final ComponentAdapter<?> getComponentAdapter(Object componentKey) {
222 ComponentAdapter adapter = componentKeyToAdapterCache.get(componentKey);
223 if (adapter == null && parent != null) {
224 adapter = parent.getComponentAdapter(componentKey);
225 }
226 return adapter;
227 }
228
229 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, ParameterName componentParameterName) {
230 // See http://jira.codehaus.org/secure/ViewIssue.jspa?key=PICO-115
231 ComponentAdapter<?> adapterByKey = getComponentAdapter((Object)componentType);
232 if (adapterByKey != null) {
233 return typeComponentAdapter(adapterByKey);
234 }
235
236 List<ComponentAdapter<T>> found = getComponentAdapters(componentType);
237
238 if (found.size() == 1) {
239 return found.get(0);
240 } else if (found.isEmpty()) {
241 if (parent != null) {
242 return parent.getComponentAdapter(componentType, componentParameterName);
243 } else {
244 return null;
245 }
246 } else {
247 if (componentParameterName != null) {
248 String parameterName = componentParameterName.getName();
249 if (parameterName != null) {
250 ComponentAdapter ca = getComponentAdapter(parameterName);
251 if (ca != null && componentType.isAssignableFrom(ca.getComponentImplementation())) {
252 return ca;
253 }
254 }
255 }
256 Class[] foundClasses = new Class[found.size()];
257 for (int i = 0; i < foundClasses.length; i++) {
258 foundClasses[i] = found.get(i).getComponentImplementation();
259 }
260
261 throw new AbstractInjector.AmbiguousComponentResolutionException(componentType, foundClasses);
262 }
263 }
264
265 public <T> List<ComponentAdapter<T>> getComponentAdapters(Class<T> componentType) {
266 if (componentType == null) {
267 return Collections.emptyList();
268 }
269 List<ComponentAdapter<T>> found = new ArrayList<ComponentAdapter<T>>();
270 for (ComponentAdapter<?> componentAdapter : getComponentAdapters()) {
271 if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
272 ComponentAdapter<T> typedComponentAdapter = typeComponentAdapter(componentAdapter);
273 found.add(typedComponentAdapter);
274 }
275 }
276 return found;
277 }
278
279 protected MutablePicoContainer addAdapterInternal(ComponentAdapter componentAdapter) {
280 Object componentKey = componentAdapter.getComponentKey();
281 if (componentKeyToAdapterCache.containsKey(componentKey)) {
282 throw new PicoCompositionException("Duplicate Keys not allowed. Duplicate for '" + componentKey + "'");
283 }
284 componentAdapters.add(componentAdapter);
285 componentKeyToAdapterCache.put(componentKey, componentAdapter);
286 return this;
287 }
288
289 /**
290 * {@inheritDoc}
291 * This method can be used to override the ComponentAdapter created by the {@link ComponentFactory}
292 * passed to the constructor of this container.
293 */
294 public MutablePicoContainer addAdapter(ComponentAdapter componentAdapter) {
295 return addAdapter(componentAdapter, this.componentProperties);
296 }
297
298 public MutablePicoContainer addAdapter(ComponentAdapter componentAdapter, Properties properties) {
299 Properties tmpProperties = (Properties)properties.clone();
300 if (AbstractBehaviorFactory.removePropertiesIfPresent(tmpProperties, Characteristics.NONE) == false && componentFactory instanceof BehaviorFactory) {
301 MutablePicoContainer container = addAdapterInternal(((BehaviorFactory)componentFactory).addComponentAdapter(
302 componentMonitor,
303 lifecycleStrategy,
304 tmpProperties,
305 componentAdapter));
306 throwIfPropertiesLeft(tmpProperties);
307 return container;
308 } else {
309 return addAdapterInternal(componentAdapter);
310 }
311
312 }
313
314
315 public ComponentAdapter removeComponent(Object componentKey) {
316 if (started) {
317 throw new PicoCompositionException("Cannot remove components after the container has started");
318 }
319 ComponentAdapter adapter = componentKeyToAdapterCache.remove(componentKey);
320 componentAdapters.remove(adapter);
321 orderedComponentAdapters.remove(adapter);
322 return adapter;
323 }
324
325 /**
326 * {@inheritDoc}
327 * The returned ComponentAdapter will be an {@link org.picocontainer.adapters.InstanceAdapter}.
328 */
329 public MutablePicoContainer addComponent(Object implOrInstance) {
330 return addComponent(implOrInstance, this.componentProperties);
331 }
332
333 private MutablePicoContainer addComponent(Object implOrInstance, Properties props) {
334 Class clazz;
335 if (implOrInstance instanceof String) {
336 addComponent((String) implOrInstance, implOrInstance);
337 }
338 if (implOrInstance instanceof Class) {
339 clazz = (Class)implOrInstance;
340 } else {
341 clazz = implOrInstance.getClass();
342 }
343 return addComponent(clazz, implOrInstance, props);
344 }
345
346
347 public MutablePicoContainer addConfig(String name, Object val) {
348 // shall be removed somehow...
349 initForConfig();
350 return addAdapterInternal(new InstanceAdapter(name, val, lifecycleStrategy, componentMonitor));
351 }
352
353 /**
354 * TODO: need for this method is being disputed
355 */
356 private void initForConfig() {
357 final String DUMMY_PICOCONTAINER_CONFIG_ITEM = "DUMMY_PICOCONTAINER_CONFIG_ITEM_";
358 if (getComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + 1) != null) {
359 return;
360 }
361 int i = 0;
362 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, DUMMY_PICOCONTAINER_CONFIG_ITEM + i);
363 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, DUMMY_PICOCONTAINER_CONFIG_ITEM + i);
364 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, 0);
365 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, 0);
366 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, false);
367 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, false);
368 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, 0L);
369 addComponent(DUMMY_PICOCONTAINER_CONFIG_ITEM + ++i, 0L);
370 }
371
372 /**
373 * {@inheritDoc}
374 * The returned ComponentAdapter will be instantiated by the {@link ComponentFactory}
375 * passed to the container's constructor.
376 */
377 public MutablePicoContainer addComponent(Object componentKey,
378 Object componentImplementationOrInstance,
379 Parameter... parameters) {
380 return this.addComponent(componentKey, componentImplementationOrInstance, this.componentProperties, parameters);
381 }
382
383 private MutablePicoContainer addComponent(Object componentKey,
384 Object componentImplementationOrInstance,
385 final Properties properties,
386 Parameter... parameters) {
387 if (parameters != null && parameters.length == 0 && parameters != Parameter.ZERO) {
388 parameters = null; // backwards compatibility! solve this better later - Paul
389 }
390 if (componentImplementationOrInstance instanceof Class) {
391 Properties tmpProperties = (Properties) properties.clone();
392 ComponentAdapter componentAdapter = componentFactory.createComponentAdapter(componentMonitor,
393 lifecycleStrategy,
394 tmpProperties,
395 componentKey,
396 (Class)componentImplementationOrInstance,
397 parameters);
398 throwIfPropertiesLeft(tmpProperties);
399 return addAdapterInternal(componentAdapter);
400 } else {
401 ComponentAdapter componentAdapter =
402 new InstanceAdapter(componentKey, componentImplementationOrInstance, lifecycleStrategy, componentMonitor);
403 return addAdapter(componentAdapter, properties);
404 }
405 }
406
407 private void throwIfPropertiesLeft(Properties tmpProperties) {
408 if(tmpProperties.size() > 0) {
409 throw new PicoCompositionException("Unprocessed Characteristics:" + tmpProperties +", refer http://picocontainer.org/unprocessed-properties-help.html");
410 }
411 }
412
413 private void addOrderedComponentAdapter(ComponentAdapter componentAdapter) {
414 if (!orderedComponentAdapters.contains(componentAdapter)) {
415 orderedComponentAdapters.add(componentAdapter);
416 }
417 }
418
419 public List getComponents() throws PicoException {
420 return getComponents(Object.class);
421 }
422
423 public <T> List<T> getComponents(Class<T> componentType) {
424 if (componentType == null) {
425 return Collections.emptyList();
426 }
427
428 Map<ComponentAdapter<T>, T> adapterToInstanceMap = new HashMap<ComponentAdapter<T>, T>();
429 for (ComponentAdapter<?> componentAdapter : componentAdapters) {
430 if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
431 ComponentAdapter<T> typedComponentAdapter = typeComponentAdapter(componentAdapter);
432 T componentInstance = getLocalInstance(typedComponentAdapter);
433
434 adapterToInstanceMap.put(typedComponentAdapter, componentInstance);
435 }
436 }
437 List<T> result = new ArrayList<T>();
438 for (ComponentAdapter componentAdapter : orderedComponentAdapters) {
439 final T componentInstance = adapterToInstanceMap.get(componentAdapter);
440 if (componentInstance != null) {
441 // may be null in the case of the "implicit" addAdapter
442 // representing "this".
443 result.add(componentInstance);
444 }
445 }
446 return result;
447 }
448
449 private <T> T getLocalInstance(ComponentAdapter<T> typedComponentAdapter) {
450 T componentInstance = typedComponentAdapter.getComponentInstance(this);
451
452 // This is to ensure all are added. (Indirect dependencies will be added
453 // from InstantiatingComponentAdapter).
454 addOrderedComponentAdapter(typedComponentAdapter);
455
456 return componentInstance;
457 }
458
459 @SuppressWarnings({ "unchecked" })
460 private static <T> ComponentAdapter<T> typeComponentAdapter(ComponentAdapter<?> componentAdapter) {
461 return (ComponentAdapter<T>)componentAdapter;
462 }
463
464 public Object getComponent(Object componentKeyOrType) {
465 Object retVal;
466 if (componentKeyOrType instanceof Class) {
467 final ComponentAdapter<?> componentAdapter = getComponentAdapter((Class<?>)componentKeyOrType, null);
468 retVal = componentAdapter == null ? null : getInstance(componentAdapter);
469 } else {
470 ComponentAdapter<?> componentAdapter = getComponentAdapter(componentKeyOrType);
471 retVal = componentAdapter == null ? null : getInstance(componentAdapter);
472 }
473 if (retVal == null) {
474 retVal = componentMonitor.noComponentFound(this, componentKeyOrType);
475 }
476 return retVal;
477 }
478
479 public <T> T getComponent(Class<T> componentType) {
480 Object o = getComponent((Object)componentType);
481 return componentType.cast(o);
482 }
483
484 private Object getInstance(ComponentAdapter componentAdapter) {
485 // check wether this is our adapter
486 // we need to check this to ensure up-down dependencies cannot be followed
487 final boolean isLocal = componentAdapters.contains(componentAdapter);
488
489 if (isLocal) {
490 Object instance;
491 try {
492 instance = componentAdapter.getComponentInstance(this);
493 } catch (AbstractInjector.CyclicDependencyException e) {
494 if (parent != null) {
495 instance = parent.getComponent(componentAdapter.getComponentKey());
496 if (instance != null) {
497 return instance;
498 }
499 }
500 throw e;
501 }
502 addOrderedComponentAdapter(componentAdapter);
503
504 return instance;
505 } else if (parent != null) {
506 return parent.getComponent(componentAdapter.getComponentKey());
507 }
508
509 return null;
510 }
511
512
513 public PicoContainer getParent() {
514 return parent;
515 }
516
517 public ComponentAdapter removeComponentByInstance(Object componentInstance) {
518 for (ComponentAdapter<?> componentAdapter : componentAdapters) {
519 if (getLocalInstance(componentAdapter).equals(componentInstance)) {
520 return removeComponent(componentAdapter.getComponentKey());
521 }
522 }
523 return null;
524 }
525
526 /**
527 * Start the components of this PicoContainer and all its logical child containers.
528 * The starting of the child container is only attempted if the parent
529 * container start successfully. The child container for which start is attempted
530 * is tracked so that upon stop, only those need to be stopped.
531 * The lifecycle operation is delegated to the component adapter,
532 * if it is an instance of {@link Behavior lifecycle manager}.
533 * The actual {@link LifecycleStrategy lifecycle strategy} supported
534 * depends on the concrete implementation of the adapter.
535 *
536 * @see Behavior
537 * @see LifecycleStrategy
538 * @see #makeChildContainer()
539 * @see #addChildContainer(PicoContainer)
540 * @see #removeChildContainer(PicoContainer)
541 */
542 public void start() {
543 if (disposed) throw new IllegalStateException("Already disposed");
544 if (started) throw new IllegalStateException("Already started");
545 started = true;
546 startAdapters();
547 childrenStarted.clear();
548 for (PicoContainer child : children) {
549 childrenStarted.add(child.hashCode());
550 if (child instanceof Startable) {
551 ((Startable)child).start();
552 }
553 }
554 }
555
556 /**
557 * Stop the components of this PicoContainer and all its logical child containers.
558 * The stopping of the child containers is only attempted for those that have been
559 * started, possibly not successfully.
560 * The lifecycle operation is delegated to the component adapter,
561 * if it is an instance of {@link Behavior lifecycle manager}.
562 * The actual {@link LifecycleStrategy lifecycle strategy} supported
563 * depends on the concrete implementation of the adapter.
564 *
565 * @see Behavior
566 * @see LifecycleStrategy
567 * @see #makeChildContainer()
568 * @see #addChildContainer(PicoContainer)
569 * @see #removeChildContainer(PicoContainer)
570 */
571 public void stop() {
572 if (disposed) throw new IllegalStateException("Already disposed");
573 if (!started) throw new IllegalStateException("Not started");
574 for (PicoContainer child : children) {
575 if (childStarted(child)) {
576 if (child instanceof Startable) {
577 ((Startable)child).stop();
578 }
579 }
580 }
581 stopAdapters();
582 started = false;
583 }
584
585 /**
586 * Checks the status of the child container to see if it's been started
587 * to prevent IllegalStateException upon stop
588 *
589 * @param child the child PicoContainer
590 *
591 * @return A boolean, <code>true</code> if the container is started
592 */
593 private boolean childStarted(PicoContainer child) {
594 return childrenStarted.contains(new Integer(child.hashCode()));
595 }
596
597 /**
598 * Dispose the components of this PicoContainer and all its logical child containers.
599 * The lifecycle operation is delegated to the component adapter,
600 * if it is an instance of {@link Behavior lifecycle manager}.
601 * The actual {@link LifecycleStrategy lifecycle strategy} supported
602 * depends on the concrete implementation of the adapter.
603 *
604 * @see Behavior
605 * @see LifecycleStrategy
606 * @see #makeChildContainer()
607 * @see #addChildContainer(PicoContainer)
608 * @see #removeChildContainer(PicoContainer)
609 */
610 public void dispose() {
611 if (disposed) throw new IllegalStateException("Already disposed");
612 for (PicoContainer child : children) {
613 if (child instanceof MutablePicoContainer) {
614 ((Disposable)child).dispose();
615 }
616 }
617 disposeAdapters();
618 disposed = true;
619 }
620
621 public MutablePicoContainer makeChildContainer() {
622 DefaultPicoContainer pc = new DefaultPicoContainer(componentFactory, lifecycleStrategy, this);
623 addChildContainer(pc);
624 return pc;
625 }
626
627 public MutablePicoContainer addChildContainer(PicoContainer child) {
628 if (children.add(child)) {
629 // @todo Should only be added if child container has also be started
630 if (started) {
631 childrenStarted.add(child.hashCode());
632 }
633 }
634 return this;
635 }
636
637 public boolean removeChildContainer(PicoContainer child) {
638 final boolean result = children.remove(child);
639 childrenStarted.remove(new Integer(child.hashCode()));
640 return result;
641 }
642
643 public MutablePicoContainer change(Properties... properties) {
644 for (Properties c : properties) {
645 Enumeration e = c.propertyNames();
646 while (e.hasMoreElements()) {
647 String s = (String)e.nextElement();
648 componentProperties.setProperty(s,c.getProperty(s));
649 }
650 }
651 return this;
652 }
653
654 public MutablePicoContainer as(Properties... properties) {
655 return new AsPropertiesPicoContainer(properties);
656 }
657
658 public void accept(PicoVisitor visitor) {
659 visitor.visitContainer(this);
660 final List<ComponentAdapter> componentAdapters = new ArrayList<ComponentAdapter>(getComponentAdapters());
661 for (ComponentAdapter componentAdapter : componentAdapters) {
662 componentAdapter.accept(visitor);
663 }
664 final List<PicoContainer> allChildren = new ArrayList<PicoContainer>(children);
665 for (PicoContainer child : allChildren) {
666 child.accept(visitor);
667 }
668 }
669
670 /**
671 * Changes monitor in the ComponentFactory, the component adapters
672 * and the child containers, if these support a ComponentMonitorStrategy.
673 * {@inheritDoc}
674 */
675 public void changeMonitor(ComponentMonitor monitor) {
676 this.componentMonitor = monitor;
677 if (lifecycleStrategy instanceof ComponentMonitorStrategy) {
678 ((ComponentMonitorStrategy)lifecycleStrategy).changeMonitor(monitor);
679 }
680 for (ComponentAdapter adapter : componentAdapters) {
681 if (adapter instanceof ComponentMonitorStrategy) {
682 ((ComponentMonitorStrategy)adapter).changeMonitor(monitor);
683 }
684 }
685 for (PicoContainer child : children) {
686 if (child instanceof ComponentMonitorStrategy) {
687 ((ComponentMonitorStrategy)child).changeMonitor(monitor);
688 }
689 }
690 }
691
692 /**
693 * Returns the first current monitor found in the ComponentFactory, the component adapters
694 * and the child containers, if these support a ComponentMonitorStrategy.
695 * {@inheritDoc}
696 *
697 * @throws PicoCompositionException if no component monitor is found in container or its children
698 */
699 public ComponentMonitor currentMonitor() {
700 return componentMonitor;
701 }
702
703 /**
704 * {@inheritDoc}
705 * Loops over all component adapters and invokes
706 * start(PicoContainer) method on the ones which are LifecycleManagers
707 */
708 private void startAdapters() {
709 Collection<ComponentAdapter<?>> adapters = getComponentAdapters();
710 for (ComponentAdapter adapter : adapters) {
711 if (adapter instanceof Behavior) {
712 Behavior behaviorAdapter = (Behavior)adapter;
713 if (behaviorAdapter.componentHasLifecycle()) {
714 // create an instance, it will be added to the ordered CA list
715 adapter.getComponentInstance(DefaultPicoContainer.this);
716 addOrderedComponentAdapter(adapter);
717 }
718 }
719 }
720 adapters = orderedComponentAdapters;
721 // clear list of started CAs
722 startedComponentAdapters.clear();
723 // clone the adapters
724 List<ComponentAdapter<?>> adaptersClone = new ArrayList<ComponentAdapter<?>>(adapters);
725 for (final ComponentAdapter adapter : adaptersClone) {
726 if (adapter instanceof Behavior) {
727 Behavior manager = (Behavior)adapter;
728 manager.start(DefaultPicoContainer.this);
729 startedComponentAdapters.add(adaptersClone.indexOf(adapter));
730 }
731 }
732 }
733
734 /**
735 * {@inheritDoc}
736 * Loops over started component adapters (in inverse order) and invokes
737 * stop(PicoContainer) method on the ones which are LifecycleManagers
738 */
739 private void stopAdapters() {
740 for (int i = startedComponentAdapters.size() - 1; 0 <= i; i--) {
741 ComponentAdapter adapter = orderedComponentAdapters.get(startedComponentAdapters.get(i));
742 if (adapter instanceof Behavior) {
743 Behavior manager = (Behavior)adapter;
744 manager.stop(DefaultPicoContainer.this);
745 }
746 }
747 }
748
749 /**
750 * {@inheritDoc}
751 * Loops over all component adapters (in inverse order) and invokes
752 * dispose(PicoContainer) method on the ones which are LifecycleManagers
753 */
754 private void disposeAdapters() {
755 for (int i = orderedComponentAdapters.size() - 1; 0 <= i; i--) {
756 ComponentAdapter adapter = orderedComponentAdapters.get(i);
757 if (adapter instanceof Behavior) {
758 Behavior manager = (Behavior)adapter;
759 manager.dispose(DefaultPicoContainer.this);
760 }
761 }
762 }
763
764
765 private class AsPropertiesPicoContainer extends AbstractDelegatingMutablePicoContainer {
766 private Properties properties;
767
768 public AsPropertiesPicoContainer(Properties... props) {
769 super(DefaultPicoContainer.this);
770 properties = (Properties) componentProperties.clone();
771 for (Properties c : props) {
772 Enumeration e = c.propertyNames();
773 while (e.hasMoreElements()) {
774 String s = (String)e.nextElement();
775 properties.setProperty(s,c.getProperty(s));
776 }
777 }
778 }
779
780 public MutablePicoContainer makeChildContainer() {
781 return getDelegate().makeChildContainer();
782 }
783
784 public MutablePicoContainer addComponent(Object componentKey,
785 Object componentImplementationOrInstance,
786 Parameter... parameters) throws PicoCompositionException {
787 return DefaultPicoContainer.this.addComponent(componentKey,
788 componentImplementationOrInstance,
789 properties,
790 parameters);
791 }
792
793 public MutablePicoContainer addComponent(Object implOrInstance) throws PicoCompositionException {
794 return DefaultPicoContainer.this.addComponent(implOrInstance, properties);
795 }
796
797 public MutablePicoContainer addAdapter(ComponentAdapter componentAdapter) throws PicoCompositionException {
798 return DefaultPicoContainer.this.addAdapter(componentAdapter, properties);
799 }
800 }
801
802 }