1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| package org.picocontainer.defaults; |
11 |
| |
12 |
| import org.picocontainer.ComponentAdapter; |
13 |
| import org.picocontainer.Parameter; |
14 |
| import org.picocontainer.PicoContainer; |
15 |
| import org.picocontainer.PicoInitializationException; |
16 |
| import org.picocontainer.PicoInstantiationException; |
17 |
| import org.picocontainer.PicoIntrospectionException; |
18 |
| import org.picocontainer.PicoVisitor; |
19 |
| |
20 |
| import java.io.Serializable; |
21 |
| import java.lang.reflect.Array; |
22 |
| import java.util.ArrayList; |
23 |
| import java.util.Collection; |
24 |
| import java.util.HashMap; |
25 |
| import java.util.HashSet; |
26 |
| import java.util.Iterator; |
27 |
| import java.util.List; |
28 |
| import java.util.Map; |
29 |
| import java.util.Set; |
30 |
| import java.util.SortedMap; |
31 |
| import java.util.SortedSet; |
32 |
| import java.util.TreeMap; |
33 |
| import java.util.TreeSet; |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| |
40 |
| |
41 |
| |
42 |
| |
43 |
| |
44 |
| |
45 |
| |
46 |
| public class CollectionComponentParameter |
47 |
| implements Parameter, Serializable { |
48 |
| |
49 |
| |
50 |
| |
51 |
| |
52 |
| public static final CollectionComponentParameter ARRAY = new CollectionComponentParameter(); |
53 |
| |
54 |
| |
55 |
| |
56 |
| |
57 |
| public static final CollectionComponentParameter ARRAY_ALLOW_EMPTY = new CollectionComponentParameter(true); |
58 |
| |
59 |
| private final boolean emptyCollection; |
60 |
| private final Class componentKeyType; |
61 |
| private final Class componentValueType; |
62 |
| |
63 |
| |
64 |
| |
65 |
| |
66 |
| |
67 |
74
| public CollectionComponentParameter() {
|
68 |
74
| this(false);
|
69 |
| } |
70 |
| |
71 |
| |
72 |
| |
73 |
| |
74 |
| |
75 |
| |
76 |
| |
77 |
144
| public CollectionComponentParameter(boolean emptyCollection) {
|
78 |
144
| this(Void.TYPE, emptyCollection);
|
79 |
| } |
80 |
| |
81 |
| |
82 |
| |
83 |
| |
84 |
| |
85 |
| |
86 |
| |
87 |
| |
88 |
| |
89 |
192
| public CollectionComponentParameter(Class componentValueType, boolean emptyCollection) {
|
90 |
192
| this(Object.class, componentValueType, emptyCollection);
|
91 |
| } |
92 |
| |
93 |
| |
94 |
| |
95 |
| |
96 |
| |
97 |
| |
98 |
| |
99 |
| |
100 |
| |
101 |
| |
102 |
196
| public CollectionComponentParameter(Class componentKeyType, Class componentValueType, boolean emptyCollection) {
|
103 |
196
| this.emptyCollection = emptyCollection;
|
104 |
196
| this.componentKeyType = componentKeyType;
|
105 |
196
| this.componentValueType = componentValueType;
|
106 |
| } |
107 |
| |
108 |
| |
109 |
| |
110 |
| |
111 |
| |
112 |
| |
113 |
| |
114 |
| |
115 |
| |
116 |
| |
117 |
| |
118 |
| |
119 |
| |
120 |
104
| public Object resolveInstance(PicoContainer container, ComponentAdapter adapter, Class expectedType)
|
121 |
| throws PicoInstantiationException { |
122 |
| |
123 |
104
| Object result = null;
|
124 |
104
| final Class collectionType = getCollectionType(expectedType);
|
125 |
104
| if (collectionType != null) {
|
126 |
98
| final Map adapterMap = getMatchingComponentAdapters(container, adapter, componentKeyType, getValueType(expectedType));
|
127 |
98
| if (Array.class.isAssignableFrom(collectionType)) {
|
128 |
42
| result = getArrayInstance(container, expectedType, adapterMap);
|
129 |
56
| } else if (Map.class.isAssignableFrom(collectionType)) {
|
130 |
26
| result = getMapInstance(container, expectedType, adapterMap);
|
131 |
30
| } else if (Collection.class.isAssignableFrom(collectionType)) {
|
132 |
30
| result = getCollectionInstance(container, expectedType, adapterMap);
|
133 |
| } else { |
134 |
0
| throw new PicoIntrospectionException(expectedType.getName() + " is not a collective type");
|
135 |
| } |
136 |
| } |
137 |
104
| return result;
|
138 |
| } |
139 |
| |
140 |
| |
141 |
| |
142 |
| |
143 |
| |
144 |
| |
145 |
| |
146 |
| |
147 |
| |
148 |
| |
149 |
| |
150 |
| |
151 |
| |
152 |
1146
| public boolean isResolvable(PicoContainer container, ComponentAdapter adapter, Class expectedType) {
|
153 |
1146
| final Class collectionType = getCollectionType(expectedType);
|
154 |
1146
| final Class valueType = getValueType(expectedType);
|
155 |
1146
| return collectionType != null && (emptyCollection || getMatchingComponentAdapters(container, adapter, componentKeyType, valueType).size() > 0);
|
156 |
| } |
157 |
| |
158 |
| |
159 |
| |
160 |
| |
161 |
| |
162 |
| |
163 |
| |
164 |
| |
165 |
| |
166 |
| |
167 |
| |
168 |
| |
169 |
10
| public void verify(PicoContainer container, ComponentAdapter adapter, Class expectedType) throws PicoIntrospectionException {
|
170 |
10
| final Class collectionType = getCollectionType(expectedType);
|
171 |
10
| if (collectionType != null) {
|
172 |
10
| final Class valueType = getValueType(expectedType);
|
173 |
10
| final Collection componentAdapters = getMatchingComponentAdapters(container, adapter, componentKeyType, valueType).values();
|
174 |
10
| if (componentAdapters.isEmpty()) {
|
175 |
4
| if (!emptyCollection) {
|
176 |
2
| throw new PicoIntrospectionException(expectedType.getName()
|
177 |
| + " not resolvable, no components of type " |
178 |
| + getValueType(expectedType).getName() |
179 |
| + " available"); |
180 |
| } |
181 |
| } else { |
182 |
6
| for (final Iterator iter = componentAdapters.iterator(); iter.hasNext();) {
|
183 |
8
| final ComponentAdapter componentAdapter = (ComponentAdapter) iter.next();
|
184 |
8
| componentAdapter.verify(container);
|
185 |
| } |
186 |
| } |
187 |
| } else { |
188 |
0
| throw new PicoIntrospectionException(expectedType.getName() + " is not a collective type");
|
189 |
| } |
190 |
8
| return;
|
191 |
| } |
192 |
| |
193 |
| |
194 |
| |
195 |
| |
196 |
| |
197 |
| |
198 |
12
| public void accept(final PicoVisitor visitor) {
|
199 |
12
| visitor.visitParameter(this);
|
200 |
| } |
201 |
| |
202 |
| |
203 |
| |
204 |
| |
205 |
| |
206 |
| |
207 |
| |
208 |
284
| protected boolean evaluate(final ComponentAdapter adapter) {
|
209 |
284
| return adapter != null;
|
210 |
| } |
211 |
| |
212 |
| |
213 |
| |
214 |
| |
215 |
| |
216 |
| |
217 |
| |
218 |
| |
219 |
| |
220 |
874
| protected Map getMatchingComponentAdapters(PicoContainer container, ComponentAdapter adapter, Class keyType, Class valueType) {
|
221 |
874
| final Map adapterMap = new HashMap();
|
222 |
874
| final PicoContainer parent = container.getParent();
|
223 |
874
| if (parent != null) {
|
224 |
26
| adapterMap.putAll(getMatchingComponentAdapters(parent, adapter, keyType, valueType));
|
225 |
| } |
226 |
874
| final Collection allAdapters = container.getComponentAdapters();
|
227 |
874
| for (final Iterator iter = allAdapters.iterator(); iter.hasNext();) {
|
228 |
1904
| final ComponentAdapter componentAdapter = (ComponentAdapter) iter.next();
|
229 |
1904
| adapterMap.remove(componentAdapter.getComponentKey());
|
230 |
| } |
231 |
874
| final List adapterList = container.getComponentAdaptersOfType(valueType);
|
232 |
874
| for (final Iterator iter = adapterList.iterator(); iter.hasNext();) {
|
233 |
320
| final ComponentAdapter componentAdapter = (ComponentAdapter) iter.next();
|
234 |
320
| final Object key = componentAdapter.getComponentKey();
|
235 |
320
| if (adapter != null && key.equals(adapter.getComponentKey())) {
|
236 |
4
| continue;
|
237 |
| } |
238 |
316
| if (keyType.isAssignableFrom(key.getClass()) && evaluate(componentAdapter)) {
|
239 |
300
| adapterMap.put(key, componentAdapter);
|
240 |
| } |
241 |
| } |
242 |
874
| return adapterMap;
|
243 |
| } |
244 |
| |
245 |
1260
| private Class getCollectionType(final Class collectionType) {
|
246 |
1260
| Class collectionClass = null;
|
247 |
1260
| if (collectionType.isArray()) {
|
248 |
720
| collectionClass = Array.class;
|
249 |
540
| } else if (Map.class.isAssignableFrom(collectionType)) {
|
250 |
76
| collectionClass = Map.class;
|
251 |
464
| } else if (Collection.class.isAssignableFrom(collectionType)) {
|
252 |
74
| collectionClass = Collection.class;
|
253 |
| } |
254 |
1260
| return collectionClass;
|
255 |
| } |
256 |
| |
257 |
1256
| private Class getValueType(final Class collectionType) {
|
258 |
1256
| Class valueType = componentValueType;
|
259 |
1256
| if (collectionType.isArray()) {
|
260 |
722
| valueType = collectionType.getComponentType();
|
261 |
| } |
262 |
1256
| return valueType;
|
263 |
| } |
264 |
| |
265 |
42
| private Object[] getArrayInstance(final PicoContainer container, final Class expectedType, final Map adapterList) {
|
266 |
42
| final Object[] result = (Object[]) Array.newInstance(expectedType.getComponentType(), adapterList.size());
|
267 |
42
| int i = 0;
|
268 |
42
| for (final Iterator iterator = adapterList.values().iterator(); iterator.hasNext();) {
|
269 |
56
| final ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
|
270 |
56
| result[i] = container.getComponentInstance(componentAdapter.getComponentKey());
|
271 |
56
| i++;
|
272 |
| } |
273 |
42
| return result;
|
274 |
| } |
275 |
| |
276 |
30
| private Collection getCollectionInstance(final PicoContainer container, final Class expectedType, final Map adapterList) {
|
277 |
30
| Class collectionType = expectedType;
|
278 |
30
| if (collectionType.isInterface()) {
|
279 |
| |
280 |
22
| if (List.class.isAssignableFrom(collectionType)) {
|
281 |
2
| collectionType = ArrayList.class;
|
282 |
| |
283 |
| |
284 |
| |
285 |
| |
286 |
20
| } else if (SortedSet.class.isAssignableFrom(collectionType)) {
|
287 |
2
| collectionType = TreeSet.class;
|
288 |
18
| } else if (Set.class.isAssignableFrom(collectionType)) {
|
289 |
2
| collectionType = HashSet.class;
|
290 |
16
| } else if (Collection.class.isAssignableFrom(collectionType)) {
|
291 |
16
| collectionType = ArrayList.class;
|
292 |
| } |
293 |
| } |
294 |
30
| try {
|
295 |
30
| Collection result = (Collection) collectionType.newInstance();
|
296 |
30
| for (final Iterator iterator = adapterList.values().iterator(); iterator.hasNext();) {
|
297 |
34
| final ComponentAdapter componentAdapter = (ComponentAdapter) iterator.next();
|
298 |
34
| result.add(container.getComponentInstance(componentAdapter.getComponentKey()));
|
299 |
| } |
300 |
30
| return result;
|
301 |
| } catch (InstantiationException e) { |
302 |
| |
303 |
| throw new PicoInitializationException(e); |
304 |
| |
305 |
| } catch (IllegalAccessException e) { |
306 |
| |
307 |
| throw new PicoInitializationException(e); |
308 |
| |
309 |
| } |
310 |
| } |
311 |
| |
312 |
26
| private Map getMapInstance(final PicoContainer container, final Class expectedType, final Map adapterList) {
|
313 |
26
| Class collectionType = expectedType;
|
314 |
26
| if (collectionType.isInterface()) {
|
315 |
| |
316 |
16
| if (SortedMap.class.isAssignableFrom(collectionType)) {
|
317 |
2
| collectionType = TreeMap.class;
|
318 |
| |
319 |
| |
320 |
14
| } else if (Map.class.isAssignableFrom(collectionType)) {
|
321 |
14
| collectionType = HashMap.class;
|
322 |
| } |
323 |
| } |
324 |
26
| try {
|
325 |
26
| Map result = (Map) collectionType.newInstance();
|
326 |
26
| for (final Iterator iterator = adapterList.entrySet().iterator(); iterator.hasNext();) {
|
327 |
48
| final Map.Entry entry = (Map.Entry) iterator.next();
|
328 |
48
| final Object key = entry.getKey();
|
329 |
48
| final ComponentAdapter componentAdapter = (ComponentAdapter) entry.getValue();
|
330 |
48
| result.put(key, container.getComponentInstance(key));
|
331 |
| } |
332 |
26
| return result;
|
333 |
| } catch (InstantiationException e) { |
334 |
| |
335 |
| throw new PicoInitializationException(e); |
336 |
| |
337 |
| } catch (IllegalAccessException e) { |
338 |
| |
339 |
| throw new PicoInitializationException(e); |
340 |
| |
341 |
| } |
342 |
| } |
343 |
| |
344 |
| } |