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: *****************************************************************************/package org.picocontainer.injectors;
009:
010: import java.lang.reflect.InvocationTargetException;
011: import java.lang.reflect.Method;
012:
013: import org.picocontainer.ComponentMonitor;
014: import org.picocontainer.LifecycleStrategy;
015: import org.picocontainer.Parameter;
016: import org.picocontainer.PicoCompositionException;
017: import org.picocontainer.PicoContainer;
018:
019: /**
020: * Injection will happen through a single method for the component.
021: *
022: * Most likely it is a method called 'inject', though that can be overridden.
023: *
024: * @author Paul Hammant
025: * @author Aslak Hellesøy
026: * @author Jon Tirsén
027: * @author Zohar Melamed
028: * @author Jörg Schaible
029: * @author Mauro Talevi
030: */
031: public class MethodInjector extends SingleMemberInjector {
032: private transient ThreadLocalCyclicDependencyGuard instantiationGuard;
033: private final String methodName;
034:
035: /**
036: * Creates a MethodInjector
037: *
038: * @param componentKey the search key for this implementation
039: * @param componentImplementation the concrete implementation
040: * @param parameters the parameters to use for the initialization
041: * @param monitor the component monitor used by this addAdapter
042: * @param lifecycleStrategy the component lifecycle strategy used by this addAdapter
043: * @param methodName the method name
044: * @param useNames use argument names when looking up dependencies
045: * @throws AbstractInjector.NotConcreteRegistrationException
046: * if the implementation is not a concrete class.
047: * @throws NullPointerException if one of the parameters is <code>null</code>
048: */
049: public MethodInjector(final Object componentKey,
050: final Class componentImplementation,
051: Parameter[] parameters, ComponentMonitor monitor,
052: LifecycleStrategy lifecycleStrategy, String methodName,
053: boolean useNames)
054: throws AbstractInjector.NotConcreteRegistrationException {
055: super (componentKey, componentImplementation, parameters,
056: monitor, lifecycleStrategy, useNames);
057: this .methodName = methodName;
058: }
059:
060: protected Method getInjectorMethod() {
061: Method[] methods = super .getComponentImplementation()
062: .getMethods();
063: for (Method method : methods) {
064: if (method.getName().equals(methodName)) {
065: return method;
066: }
067: }
068: return null;
069: }
070:
071: public Object getComponentInstance(final PicoContainer container)
072: throws PicoCompositionException {
073: if (instantiationGuard == null) {
074: instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
075: public Object run() {
076: Method method;
077: Object inst = null;
078: try {
079: method = getInjectorMethod();
080: } catch (AmbiguousComponentResolutionException e) {
081: e.setComponent(getComponentImplementation());
082: throw e;
083: }
084: ComponentMonitor componentMonitor = currentMonitor();
085: try {
086: componentMonitor.instantiating(container,
087: MethodInjector.this , null);
088: long startTime = System.currentTimeMillis();
089: Object[] parameters = null;
090: inst = getComponentImplementation()
091: .newInstance();
092: if (method != null) {
093: parameters = getMemberArguments(
094: guardedContainer, method);
095: method.invoke(inst, parameters);
096: }
097: componentMonitor.instantiated(container,
098: MethodInjector.this , null, inst,
099: parameters, System.currentTimeMillis()
100: - startTime);
101: return inst;
102: } catch (InvocationTargetException e) {
103: componentMonitor.instantiationFailed(container,
104: MethodInjector.this , null, e);
105: if (e.getTargetException() instanceof RuntimeException) {
106: throw (RuntimeException) e
107: .getTargetException();
108: } else if (e.getTargetException() instanceof Error) {
109: throw (Error) e.getTargetException();
110: }
111: throw new PicoCompositionException(e
112: .getTargetException());
113: } catch (InstantiationException e) {
114: return caughtInstantiationException(
115: componentMonitor, null, e, container);
116: } catch (IllegalAccessException e) {
117: return caughtIllegalAccessException(
118: componentMonitor, method, inst, e);
119:
120: }
121: }
122: };
123: }
124: instantiationGuard.setGuardedContainer(container);
125: return instantiationGuard.observe(getComponentImplementation());
126: }
127:
128: protected Object[] getMemberArguments(PicoContainer container,
129: final Method method) {
130: return super .getMemberArguments(container, method, method
131: .getParameterTypes(), getBindings(method
132: .getParameterAnnotations()));
133: }
134:
135: public void verify(final PicoContainer container)
136: throws PicoCompositionException {
137: if (verifyingGuard == null) {
138: verifyingGuard = new ThreadLocalCyclicDependencyGuard() {
139: public Object run() {
140: final Method method = getInjectorMethod();
141: final Class[] parameterTypes = method
142: .getParameterTypes();
143: final Parameter[] currentParameters = parameters != null ? parameters
144: : createDefaultParameters(parameterTypes);
145: for (int i = 0; i < currentParameters.length; i++) {
146: currentParameters[i].verify(container,
147: MethodInjector.this , parameterTypes[i],
148: new ParameterNameBinding(
149: getParanamer(),
150: getComponentImplementation(),
151: method, i), useNames(),
152: getBindings(method
153: .getParameterAnnotations())[i]);
154: }
155: return null;
156: }
157: };
158: }
159: verifyingGuard.setGuardedContainer(container);
160: verifyingGuard.observe(getComponentImplementation());
161: }
162:
163: public String getDescriptor() {
164: return "MethodInjector-";
165: }
166:
167: }
|