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øy
078 * @author Jon Tirsé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 }