PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/picocontainer-2.10.2/org/picocontainer/injectors/IterativeInjector.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 320 lines | 268 code | 34 blank | 18 comment | 47 complexity | da5dbe3fa6b1ef55cd6a8d3096e5cd7d MD5 | raw file
  1. package org.picocontainer.injectors;
  2. import org.picocontainer.ComponentMonitor;
  3. import org.picocontainer.LifecycleStrategy;
  4. import org.picocontainer.Parameter;
  5. import org.picocontainer.NameBinding;
  6. import org.picocontainer.PicoCompositionException;
  7. import org.picocontainer.PicoContainer;
  8. import org.picocontainer.annotations.Bind;
  9. import java.lang.reflect.AccessibleObject;
  10. import java.lang.reflect.Constructor;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.lang.reflect.Member;
  13. import java.lang.reflect.Method;
  14. import java.lang.reflect.Type;
  15. import java.lang.reflect.TypeVariable;
  16. import java.lang.annotation.Annotation;
  17. import java.security.AccessController;
  18. import java.security.PrivilegedAction;
  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.HashSet;
  22. import java.util.List;
  23. import java.util.Set;
  24. import com.thoughtworks.paranamer.Paranamer;
  25. import com.thoughtworks.paranamer.CachingParanamer;
  26. import com.thoughtworks.paranamer.AdaptiveParanamer;
  27. import com.thoughtworks.paranamer.AnnotationParanamer;
  28. /**
  29. * Injection will happen iteratively after component instantiation
  30. */
  31. public abstract class IterativeInjector<T> extends AbstractInjector<T> {
  32. private transient ThreadLocalCyclicDependencyGuard instantiationGuard;
  33. protected transient List<AccessibleObject> injectionMembers;
  34. protected transient Type[] injectionTypes;
  35. protected transient Annotation[] bindings;
  36. private transient Paranamer paranamer;
  37. /**
  38. * Constructs a IterativeInjector
  39. *
  40. * @param componentKey the search key for this implementation
  41. * @param componentImplementation the concrete implementation
  42. * @param parameters the parameters to use for the initialization
  43. * @param monitor the component monitor used by this addAdapter
  44. * @param useNames use argument names when looking up dependencies
  45. * @throws org.picocontainer.injectors.AbstractInjector.NotConcreteRegistrationException
  46. * if the implementation is not a concrete class.
  47. * @throws NullPointerException if one of the parameters is <code>null</code>
  48. */
  49. public IterativeInjector(final Object componentKey, final Class componentImplementation, Parameter[] parameters, ComponentMonitor monitor,
  50. boolean useNames) throws NotConcreteRegistrationException {
  51. super(componentKey, componentImplementation, parameters, monitor, useNames);
  52. }
  53. protected Constructor getConstructor() {
  54. Object retVal = AccessController.doPrivileged(new PrivilegedAction<Object>() {
  55. public Object run() {
  56. try {
  57. return getComponentImplementation().getConstructor((Class[])null);
  58. } catch (NoSuchMethodException e) {
  59. return new PicoCompositionException(e);
  60. } catch (SecurityException e) {
  61. return new PicoCompositionException(e);
  62. }
  63. }
  64. });
  65. if (retVal instanceof Constructor) {
  66. return (Constructor) retVal;
  67. } else {
  68. throw (PicoCompositionException) retVal;
  69. }
  70. }
  71. private Parameter[] getMatchingParameterListForSetters(PicoContainer container) throws PicoCompositionException {
  72. if (injectionMembers == null) {
  73. initializeInjectionMembersAndTypeLists();
  74. }
  75. final List<Object> matchingParameterList = new ArrayList<Object>(Collections.nCopies(injectionMembers.size(), null));
  76. final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(injectionTypes);
  77. final Set<Integer> nonMatchingParameterPositions = matchParameters(container, matchingParameterList, currentParameters);
  78. final Set<Type> unsatisfiableDependencyTypes = new HashSet<Type>();
  79. for (int i = 0; i < matchingParameterList.size(); i++) {
  80. if (matchingParameterList.get(i) == null) {
  81. unsatisfiableDependencyTypes.add(injectionTypes[i]);
  82. }
  83. }
  84. if (unsatisfiableDependencyTypes.size() > 0) {
  85. unsatisfiedDependencies(container, unsatisfiableDependencyTypes);
  86. } else if (nonMatchingParameterPositions.size() > 0) {
  87. throw new PicoCompositionException("Following parameters do not match any of the injectionMembers for " + getComponentImplementation() + ": " + nonMatchingParameterPositions.toString());
  88. }
  89. return matchingParameterList.toArray(new Parameter[matchingParameterList.size()]);
  90. }
  91. private Set<Integer> matchParameters(PicoContainer container, List<Object> matchingParameterList, Parameter[] currentParameters) {
  92. Set<Integer> unmatchedParameters = new HashSet<Integer>();
  93. for (int i = 0; i < currentParameters.length; i++) {
  94. if (!matchParameter(container, matchingParameterList, currentParameters[i])) {
  95. unmatchedParameters.add(i);
  96. }
  97. }
  98. return unmatchedParameters;
  99. }
  100. private boolean matchParameter(PicoContainer container, List<Object> matchingParameterList, Parameter parameter) {
  101. for (int j = 0; j < injectionTypes.length; j++) {
  102. Object o = matchingParameterList.get(j);
  103. if (o == null
  104. && parameter.resolve(container, this, null, injectionTypes[j],
  105. makeParameterNameImpl(injectionMembers.get(j)),
  106. useNames(), bindings[j]).isResolved()) {
  107. matchingParameterList.set(j, parameter);
  108. return true;
  109. }
  110. }
  111. return false;
  112. }
  113. protected NameBinding makeParameterNameImpl(AccessibleObject member) {
  114. if (paranamer == null) {
  115. paranamer = new CachingParanamer(new AnnotationParanamer(new AdaptiveParanamer()));
  116. }
  117. return new ParameterNameBinding(paranamer, member, 0);
  118. }
  119. protected void unsatisfiedDependencies(PicoContainer container, Set<Type> unsatisfiableDependencyTypes) {
  120. throw new UnsatisfiableDependenciesException(this, null, unsatisfiableDependencyTypes, container);
  121. }
  122. public T getComponentInstance(final PicoContainer container, Type into) throws PicoCompositionException {
  123. final Constructor constructor = getConstructor();
  124. if (instantiationGuard == null) {
  125. instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
  126. public Object run() {
  127. final Parameter[] matchingParameters = getMatchingParameterListForSetters(guardedContainer);
  128. Object componentInstance = makeInstance(container, constructor, currentMonitor());
  129. return decorateComponentInstance(matchingParameters, currentMonitor(), componentInstance, container, guardedContainer);
  130. }
  131. };
  132. }
  133. instantiationGuard.setGuardedContainer(container);
  134. return (T) instantiationGuard.observe(getComponentImplementation());
  135. }
  136. private Object decorateComponentInstance(Parameter[] matchingParameters, ComponentMonitor componentMonitor, Object componentInstance, PicoContainer container, PicoContainer guardedContainer) {
  137. AccessibleObject member = null;
  138. Object injected[] = new Object[injectionMembers.size()];
  139. Object lastReturn = null;
  140. try {
  141. for (int i = 0; i < injectionMembers.size(); i++) {
  142. member = injectionMembers.get(i);
  143. if (matchingParameters[i] != null) {
  144. Object toInject = matchingParameters[i].resolve(guardedContainer, this, null, injectionTypes[i],
  145. makeParameterNameImpl(injectionMembers.get(i)),
  146. useNames(), bindings[i]).resolveInstance();
  147. Object rv = componentMonitor.invoking(container, this, (Member) member, componentInstance, new Object[] {toInject});
  148. if (rv == ComponentMonitor.KEEP) {
  149. long str = System.currentTimeMillis();
  150. lastReturn = injectIntoMember(member, componentInstance, toInject);
  151. componentMonitor.invoked(container, this, (Member) member, componentInstance, System.currentTimeMillis() - str, new Object[] {toInject}, lastReturn);
  152. } else {
  153. lastReturn = rv;
  154. }
  155. injected[i] = toInject;
  156. }
  157. }
  158. return memberInvocationReturn(lastReturn, member, componentInstance);
  159. } catch (InvocationTargetException e) {
  160. return caughtInvocationTargetException(componentMonitor, (Member) member, componentInstance, e);
  161. } catch (IllegalAccessException e) {
  162. return caughtIllegalAccessException(componentMonitor, (Member) member, componentInstance, e);
  163. }
  164. }
  165. protected abstract Object memberInvocationReturn(Object lastReturn, AccessibleObject member, Object instance);
  166. private Object makeInstance(PicoContainer container, Constructor constructor, ComponentMonitor componentMonitor) {
  167. long startTime = System.currentTimeMillis();
  168. Constructor constructorToUse = componentMonitor.instantiating(container,
  169. IterativeInjector.this, constructor);
  170. Object componentInstance;
  171. try {
  172. componentInstance = newInstance(constructorToUse, null);
  173. } catch (InvocationTargetException e) {
  174. componentMonitor.instantiationFailed(container, IterativeInjector.this, constructorToUse, e);
  175. if (e.getTargetException() instanceof RuntimeException) {
  176. throw (RuntimeException)e.getTargetException();
  177. } else if (e.getTargetException() instanceof Error) {
  178. throw (Error)e.getTargetException();
  179. }
  180. throw new PicoCompositionException(e.getTargetException());
  181. } catch (InstantiationException e) {
  182. return caughtInstantiationException(componentMonitor, constructor, e, container);
  183. } catch (IllegalAccessException e) {
  184. return caughtIllegalAccessException(componentMonitor, constructor, e, container);
  185. }
  186. componentMonitor.instantiated(container,
  187. IterativeInjector.this,
  188. constructorToUse,
  189. componentInstance,
  190. null,
  191. System.currentTimeMillis() - startTime);
  192. return componentInstance;
  193. }
  194. @Override
  195. public Object decorateComponentInstance(final PicoContainer container, Type into, final T instance) {
  196. if (instantiationGuard == null) {
  197. instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
  198. public Object run() {
  199. final Parameter[] matchingParameters = getMatchingParameterListForSetters(guardedContainer);
  200. return decorateComponentInstance(matchingParameters, currentMonitor(), instance, container, guardedContainer);
  201. }
  202. };
  203. }
  204. instantiationGuard.setGuardedContainer(container);
  205. return instantiationGuard.observe(getComponentImplementation());
  206. }
  207. protected abstract Object injectIntoMember(AccessibleObject member, Object componentInstance, Object toInject) throws IllegalAccessException, InvocationTargetException;
  208. @Override
  209. public void verify(final PicoContainer container) throws PicoCompositionException {
  210. if (verifyingGuard == null) {
  211. verifyingGuard = new ThreadLocalCyclicDependencyGuard() {
  212. public Object run() {
  213. final Parameter[] currentParameters = getMatchingParameterListForSetters(guardedContainer);
  214. for (int i = 0; i < currentParameters.length; i++) {
  215. currentParameters[i].verify(container, IterativeInjector.this, injectionTypes[i],
  216. makeParameterNameImpl(injectionMembers.get(i)), useNames(), bindings[i]);
  217. }
  218. return null;
  219. }
  220. };
  221. }
  222. verifyingGuard.setGuardedContainer(container);
  223. verifyingGuard.observe(getComponentImplementation());
  224. }
  225. protected void initializeInjectionMembersAndTypeLists() {
  226. injectionMembers = new ArrayList<AccessibleObject>();
  227. List<Annotation> bingingIds = new ArrayList<Annotation>();
  228. final List<String> nameList = new ArrayList<String>();
  229. final List<Type> typeList = new ArrayList<Type>();
  230. final Method[] methods = getMethods();
  231. for (final Method method : methods) {
  232. final Type[] parameterTypes = method.getGenericParameterTypes();
  233. fixGenericParameterTypes(method, parameterTypes);
  234. // We're only interested if there is only one parameter and the method name is bean-style.
  235. if (parameterTypes.length == 1) {
  236. boolean isInjector = isInjectorMethod(method);
  237. if (isInjector) {
  238. injectionMembers.add(method);
  239. nameList.add(getName(method));
  240. typeList.add(box(parameterTypes[0]));
  241. bingingIds.add(getBindings(method, 0));
  242. }
  243. }
  244. }
  245. injectionTypes = typeList.toArray(new Type[0]);
  246. bindings = bingingIds.toArray(new Annotation[0]);
  247. }
  248. protected String getName(Method method) {
  249. return null;
  250. }
  251. private void fixGenericParameterTypes(Method method, Type[] parameterTypes) {
  252. for (int i = 0; i < parameterTypes.length; i++) {
  253. Type parameterType = parameterTypes[i];
  254. if (parameterType instanceof TypeVariable) {
  255. parameterTypes[i] = method.getParameterTypes()[i];
  256. }
  257. }
  258. }
  259. private Annotation getBindings(Method method, int i) {
  260. Annotation[][] parameterAnnotations = method.getParameterAnnotations();
  261. if (parameterAnnotations.length >= i +1 ) {
  262. Annotation[] o = parameterAnnotations[i];
  263. for (Annotation annotation : o) {
  264. if (annotation.annotationType().getAnnotation(Bind.class) != null) {
  265. return annotation;
  266. }
  267. }
  268. return null;
  269. }
  270. //TODO - what's this ?
  271. if (parameterAnnotations != null) {
  272. //return ((Bind) method.getAnnotation(Bind.class)).id();
  273. }
  274. return null;
  275. }
  276. protected boolean isInjectorMethod(Method method) {
  277. return false;
  278. }
  279. private Method[] getMethods() {
  280. return (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
  281. public Object run() {
  282. return getComponentImplementation().getMethods();
  283. }
  284. });
  285. }
  286. }