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