KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > picocontainer > defaults > ConstructorInjectionComponentAdapter


1 /*****************************************************************************
2  * Copyright (c) PicoContainer Organization. All rights reserved. *
3  * ------------------------------------------------------------------------- *
4  * The software in this package is published under the terms of the BSD *
5  * style license a copy of which has been included with this distribution in *
6  * the LICENSE.txt file. *
7  * *
8  * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant *
9  *****************************************************************************/

10
11 package org.picocontainer.defaults;
12
13 import org.picocontainer.Parameter;
14 import org.picocontainer.PicoContainer;
15 import org.picocontainer.PicoInitializationException;
16 import org.picocontainer.PicoIntrospectionException;
17
18 import java.lang.reflect.Constructor JavaDoc;
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.lang.reflect.Modifier JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Comparator JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28
29 /**
30  * Instantiates components using Constructor Injection.
31  * <em>
32  * Note that this class doesn't cache instances. If you want caching,
33  * use a {@link CachingComponentAdapter} around this one.
34  * </em>
35  *
36  * @author Paul Hammant
37  * @author Aslak Helles&oslash;y
38  * @author Jon Tirs&eacute;n
39  * @author Zohar Melamed
40  * @author J&ouml;rg Schaible
41  * @version $Revision: 1840 $
42  */

43 public class ConstructorInjectionComponentAdapter extends InstantiatingComponentAdapter {
44     private transient List JavaDoc sortedMatchingConstructors;
45     private transient Guard instantiationGuard;
46     private ComponentMonitor componentMonitor;
47
48     private static abstract class Guard extends ThreadLocalCyclicDependencyGuard {
49         protected PicoContainer guardedContainer;
50
51         private void setArguments(PicoContainer container) {
52             this.guardedContainer = container;
53         }
54     }
55
56     /**
57      * Explicitly specifies parameters. If parameters are null, default parameters
58      * will be used.
59      */

60     public ConstructorInjectionComponentAdapter(final Object JavaDoc componentKey,
61                                                 final Class JavaDoc componentImplementation,
62                                                 Parameter[] parameters,
63                                                 boolean allowNonPublicClasses,
64                                                 ComponentMonitor componentMonitor) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
65         super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
66         this.componentMonitor = componentMonitor;
67     }
68
69     public ConstructorInjectionComponentAdapter(Object JavaDoc componentKey, Class JavaDoc componentImplementation, Parameter[] parameters) {
70         this(componentKey, componentImplementation, parameters, false, NullComponentMonitor.getInstance());
71     }
72
73     /**
74      * Use default parameters.
75      */

76     public ConstructorInjectionComponentAdapter(Object JavaDoc componentKey,
77                                                 Class JavaDoc componentImplementation) throws AssignabilityRegistrationException, NotConcreteRegistrationException {
78         this(componentKey, componentImplementation, null);
79     }
80
81     protected Constructor JavaDoc getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
82         Constructor JavaDoc greediestConstructor = null;
83         final Set JavaDoc conflicts = new HashSet JavaDoc();
84         final Set JavaDoc unsatisfiableDependencyTypes = new HashSet JavaDoc();
85         if (sortedMatchingConstructors == null) {
86             sortedMatchingConstructors = getSortedMatchingConstructors();
87         }
88         int lastSatisfiableConstructorSize = -1;
89         for (int i = 0; i < sortedMatchingConstructors.size(); i++) {
90             boolean failedDependency = false;
91             Constructor JavaDoc constructor = (Constructor JavaDoc) sortedMatchingConstructors.get(i);
92             Class JavaDoc[] parameterTypes = constructor.getParameterTypes();
93             Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
94
95             // remember: all constructors with less arguments than the given parameters are filtered out already
96
for (int j = 0; j < currentParameters.length; j++) {
97                 // check wether this constructor is statisfiable
98
if (currentParameters[j].isResolvable(container, this, parameterTypes[j])) {
99                     continue;
100                 }
101                 unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
102                 failedDependency = true;
103                 break;
104             }
105
106             if (greediestConstructor != null && parameterTypes.length != lastSatisfiableConstructorSize) {
107                 if (conflicts.isEmpty()) {
108                     // we found our match [aka. greedy and satisfied]
109
return greediestConstructor;
110                 } else {
111                     // fits although not greedy
112
conflicts.add(constructor);
113                 }
114             } else if (!failedDependency && lastSatisfiableConstructorSize == parameterTypes.length) {
115                 // satisfied and same size as previous one?
116
conflicts.add(constructor);
117                 conflicts.add(greediestConstructor);
118             } else if (!failedDependency) {
119                 greediestConstructor = constructor;
120                 lastSatisfiableConstructorSize = parameterTypes.length;
121             }
122         }
123         if (!conflicts.isEmpty()) {
124             throw new TooManySatisfiableConstructorsException(getComponentImplementation(), conflicts);
125         } else if (greediestConstructor == null && !unsatisfiableDependencyTypes.isEmpty()) {
126             throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
127         } else if (greediestConstructor == null) {
128             // be nice to the user, show all constructors that were filtered out
129
final Set JavaDoc nonMatching = new HashSet JavaDoc();
130             final Constructor JavaDoc[] constructors = getComponentImplementation().getDeclaredConstructors();
131             for (int i = 0; i < constructors.length; i++) {
132                 nonMatching.add(constructors[i]);
133             }
134             throw new PicoInitializationException("Either do the specified parameters not match any of the following constructors: " + nonMatching.toString() + " or the constructors were not accessible for '" + getComponentImplementation() + "'");
135         }
136         return greediestConstructor;
137     }
138
139     public Object JavaDoc getComponentInstance(PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
140         if (instantiationGuard == null) {
141             instantiationGuard = new Guard() {
142                 public Object JavaDoc run() {
143                     final Constructor JavaDoc constructor;
144                     try {
145                         constructor = getGreediestSatisfiableConstructor(guardedContainer);
146                     } catch (AmbiguousComponentResolutionException e) {
147                         e.setComponent(getComponentImplementation());
148                         throw e;
149                     }
150                     try {
151                         Object JavaDoc[] parameters = getConstructorArguments(guardedContainer, constructor);
152                         componentMonitor.instantiating(constructor);
153                         long startTime = System.currentTimeMillis();
154                         Object JavaDoc inst = newInstance(constructor, parameters);
155                         componentMonitor.instantiated(constructor, startTime, System.currentTimeMillis() - startTime);
156                         return inst;
157                     } catch (InvocationTargetException JavaDoc e) {
158                         componentMonitor.instantiationFailed(constructor, e);
159                         if (e.getTargetException() instanceof RuntimeException JavaDoc) {
160                             throw (RuntimeException JavaDoc) e.getTargetException();
161                         } else if (e.getTargetException() instanceof Error JavaDoc) {
162                             throw (Error JavaDoc) e.getTargetException();
163                         }
164                         throw new PicoInvocationTargetInitializationException(e.getTargetException());
165                     } catch (InstantiationException JavaDoc e) {
166                         // can't get here because checkConcrete() will catch it earlier, but see PICO-191
167
///CLOVER:OFF
168
componentMonitor.instantiationFailed(constructor, e);
169                         throw new PicoInitializationException("Should never get here");
170                         ///CLOVER:ON
171
} catch (IllegalAccessException JavaDoc e) {
172                         // can't get here because either filtered or access mode set
173
///CLOVER:OFF
174
componentMonitor.instantiationFailed(constructor, e);
175                         throw new PicoInitializationException(e);
176                         ///CLOVER:ON
177
}
178                 }
179             };
180         }
181         instantiationGuard.setArguments(container);
182         return instantiationGuard.observe(getComponentImplementation());
183     }
184
185     protected Object JavaDoc[] getConstructorArguments(PicoContainer container, Constructor JavaDoc ctor) {
186         Class JavaDoc[] parameterTypes = ctor.getParameterTypes();
187         Object JavaDoc[] result = new Object JavaDoc[parameterTypes.length];
188         Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
189
190         for (int i = 0; i < currentParameters.length; i++) {
191             result[i] = currentParameters[i].resolveInstance(container, this, parameterTypes[i]);
192         }
193         return result;
194     }
195
196     private List JavaDoc getSortedMatchingConstructors() {
197         List JavaDoc matchingConstructors = new ArrayList JavaDoc();
198         Constructor JavaDoc[] allConstructors = getComponentImplementation().getDeclaredConstructors();
199         // filter out all constructors that will definately not match
200
Constructor JavaDoc constructor;
201         for (int i = 0; i < allConstructors.length; i++) {
202             constructor = allConstructors[i];
203             if ((parameters == null || constructor.getParameterTypes().length == parameters.length)
204                     && (allowNonPublicClasses || (constructor.getModifiers() & Modifier.PUBLIC) != 0)) {
205                 matchingConstructors.add(constructor);
206             }
207         }
208         // optimize list of constructors moving the longest at the beginning
209
if (parameters == null) {
210             Collections.sort(matchingConstructors, new Comparator JavaDoc() {
211                 public int compare(Object JavaDoc arg0, Object JavaDoc arg1) {
212                     return ((Constructor JavaDoc) arg1).getParameterTypes().length - ((Constructor JavaDoc) arg0).getParameterTypes().length;
213                 }
214             });
215         }
216         return matchingConstructors;
217     }
218 }
219
Popular Tags