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 org.picocontainer.ComponentAdapter;
013 import org.picocontainer.Parameter;
014 import org.picocontainer.PicoContainer;
015 import org.picocontainer.PicoVisitor;
016
017
018 /**
019 * A ComponentParameter should be used to pass in a particular component as argument to a
020 * different component's constructor. This is particularly useful in cases where several
021 * components of the same type have been registered, but with a different key. Passing a
022 * ComponentParameter as a parameter when registering a component will give PicoContainer a hint
023 * about what other component to use in the constructor. Collecting parameter types are
024 * supported for {@link java.lang.reflect.Array},{@link java.util.Collection}and
025 * {@link java.util.Map}.
026 *
027 * @author Jon Tirsén
028 * @author Aslak Hellesøy
029 * @author Jörg Schaible
030 * @author Thomas Heller
031 * @version $Revision: 2285 $
032 */
033 public class ComponentParameter
034 extends BasicComponentParameter {
035
036 /**
037 * <code>DEFAULT</code> is an instance of ComponentParameter using the default constructor.
038 */
039 public static final ComponentParameter DEFAULT = new ComponentParameter();
040 /**
041 * Use <code>ARRAY</code> as {@link Parameter}for an Array that must have elements.
042 */
043 public static final ComponentParameter ARRAY = new ComponentParameter(false);
044 /**
045 * Use <code>ARRAY_ALLOW_EMPTY</code> as {@link Parameter}for an Array that may have no
046 * elements.
047 */
048 public static final ComponentParameter ARRAY_ALLOW_EMPTY = new ComponentParameter(true);
049
050 private final Parameter collectionParameter;
051
052 /**
053 * Expect a parameter matching a component of a specific key.
054 *
055 * @param componentKey the key of the desired component
056 */
057 public ComponentParameter(Object componentKey) {
058 this(componentKey, null);
059 }
060
061 /**
062 * Expect any scalar paramter of the appropriate type or an {@link java.lang.reflect.Array}.
063 */
064 public ComponentParameter() {
065 this(false);
066 }
067
068 /**
069 * Expect any scalar paramter of the appropriate type or an {@link java.lang.reflect.Array}.
070 * Resolve the parameter even if no compoennt is of the array's component type.
071 *
072 * @param emptyCollection <code>true</code> allows an Array to be empty
073 * @since 1.1
074 */
075 public ComponentParameter(boolean emptyCollection) {
076 this(null, emptyCollection ? CollectionComponentParameter.ARRAY_ALLOW_EMPTY : CollectionComponentParameter.ARRAY);
077 }
078
079 /**
080 * Expect any scalar paramter of the appropriate type or the collecting type
081 * {@link java.lang.reflect.Array},{@link java.util.Collection}or {@link java.util.Map}.
082 * The components in the collection will be of the specified type.
083 *
084 * @param componentValueType the component's type (ignored for an Array)
085 * @param emptyCollection <code>true</code> allows the collection to be empty
086 * @since 1.1
087 */
088 public ComponentParameter(Class componentValueType, boolean emptyCollection) {
089 this(null, new CollectionComponentParameter(componentValueType, emptyCollection));
090 }
091
092 /**
093 * Expect any scalar paramter of the appropriate type or the collecting type
094 * {@link java.lang.reflect.Array},{@link java.util.Collection}or {@link java.util.Map}.
095 * The components in the collection will be of the specified type and their adapter's key
096 * must have a particular type.
097 *
098 * @param componentKeyType the component adapter's key type
099 * @param componentValueType the component's type (ignored for an Array)
100 * @param emptyCollection <code>true</code> allows the collection to be empty
101 * @since 1.1
102 */
103 public ComponentParameter(Class componentKeyType, Class componentValueType, boolean emptyCollection) {
104 this(null, new CollectionComponentParameter(componentKeyType, componentValueType, emptyCollection));
105 }
106
107 private ComponentParameter(Object componentKey, Parameter collectionParameter) {
108 super(componentKey);
109 this.collectionParameter = collectionParameter;
110 }
111
112 public Object resolveInstance(PicoContainer container, ComponentAdapter adapter, Class expectedType) {
113 // type check is done in isResolvable
114 Object result = super.resolveInstance(container, adapter, expectedType);
115 if (result == null && collectionParameter != null) {
116 result = collectionParameter.resolveInstance(container, adapter, expectedType);
117 }
118 return result;
119 }
120
121 public boolean isResolvable(PicoContainer container, ComponentAdapter adapter, Class expectedType) {
122 if (!super.isResolvable(container, adapter, expectedType)) {
123 if (collectionParameter != null) {
124 return collectionParameter.isResolvable(container, adapter, expectedType);
125 }
126 return false;
127 }
128 return true;
129 }
130
131 public void verify(PicoContainer container, ComponentAdapter adapter, Class expectedType) {
132 try {
133 super.verify(container, adapter, expectedType);
134 } catch (UnsatisfiableDependenciesException e) {
135 if (collectionParameter != null) {
136 collectionParameter.verify(container, adapter, expectedType);
137 return;
138 }
139 throw e;
140 }
141 }
142
143 /**
144 * Accept the visitor for the current {@link Parameter}. If internally a
145 * {@link CollectionComponentParameter}is used, it is visited also.
146 *
147 * @see org.picocontainer.defaults.BasicComponentParameter#accept(org.picocontainer.PicoVisitor)
148 */
149 public void accept(PicoVisitor visitor) {
150 super.accept(visitor);
151 if (collectionParameter != null) {
152 collectionParameter.accept(visitor);
153 }
154 }
155 }