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