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 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant   *
009 *****************************************************************************/
010
011package org.picocontainer.injectors;
012
013import java.lang.reflect.AccessibleObject;
014import java.security.AccessController;
015import java.security.PrivilegedAction;
016import java.util.Properties;
017import org.picocontainer.Characteristics;
018import org.picocontainer.ComponentAdapter;
019import org.picocontainer.ComponentMonitor;
020import org.picocontainer.LifecycleStrategy;
021import org.picocontainer.Parameter;
022import org.picocontainer.PicoCompositionException;
023import org.picocontainer.annotations.Inject;
024import org.picocontainer.behaviors.AbstractBehaviorFactory;
025
026/**
027 * Creates injector instances, depending on the injection characteristics of the component class. 
028 * It will attempt to create a component adapter with - in order of priority:
029 * <ol>
030 *  <li>Annotated field injection: if annotation {@link org.picocontainer.annotations.Inject} is found for field</li>
031 *  <li>Annotated method injection: if annotation {@link org.picocontainer.annotations.Inject} is found for method</li>
032 *  <li>Setter injection: if {@link Characteristics.SDI} is found</li>
033 *  <li>Method injection: if {@link Characteristics.METHOD_INJECTION} if found</li>
034 *  <li>Constructor injection (the default, must find {@link Characteristics.CDI})</li>
035 * </ol>
036 *
037 * @author Paul Hammant
038 * @author Mauro Talevi
039 * @see AnnotatedFieldInjection
040 * @see AnnotatedMethodInjection
041 * @see SetterInjection
042 * @see MethodInjection
043 * @see ConstructorInjection
044 */
045@SuppressWarnings("serial")
046public class AdaptingInjection extends AbstractInjectionFactory {
047
048
049        public <T> ComponentAdapter<T> createComponentAdapter(ComponentMonitor componentMonitor,
050                                                   LifecycleStrategy lifecycleStrategy,
051                                                   Properties componentProperties,
052                                                   Object componentKey,
053                                                   Class<T> componentImplementation,
054                                                   Parameter... parameters) throws PicoCompositionException {
055        ComponentAdapter<T> componentAdapter = null;
056        
057        componentAdapter = fieldAnnotatedInjectionAdapter(componentImplementation,
058                               componentMonitor,
059                               lifecycleStrategy,
060                               componentProperties,
061                               componentKey,
062                               componentAdapter,
063                               parameters);
064
065        if (componentAdapter != null) {
066            return componentAdapter;
067        }
068
069
070        componentAdapter = methodAnnotatedInjectionAdapter(componentImplementation,
071                                                           componentMonitor,
072                                                           lifecycleStrategy,
073                                                           componentProperties,
074                                                           componentKey,
075                                                           componentAdapter,
076                                                           parameters);
077
078        if (componentAdapter != null) {
079            return componentAdapter;
080        }
081
082        componentAdapter = setterInjectionAdapter(componentProperties,
083                                                 componentMonitor,
084                                                 lifecycleStrategy,
085                                                 componentKey,
086                                                 componentImplementation,
087                                                 componentAdapter,
088                                                 parameters);
089
090        if (componentAdapter != null) {
091            return componentAdapter;
092        }
093
094        componentAdapter = methodInjectionAdapter(componentProperties,
095                                                 componentMonitor,
096                                                 lifecycleStrategy,
097                                                 componentKey,
098                                                 componentImplementation,
099                                                 componentAdapter,
100                                                 parameters);
101
102        if (componentAdapter != null) {
103            return componentAdapter;
104        }
105
106
107        return defaultInjectionAdapter(componentProperties,
108                                    componentMonitor,
109                                    lifecycleStrategy,
110                                    componentKey,
111                                    componentImplementation,
112                                    parameters);
113    }
114
115    private <T> ComponentAdapter<T> defaultInjectionAdapter(Properties componentProperties,
116                                                  ComponentMonitor componentMonitor,
117                                                  LifecycleStrategy lifecycleStrategy,
118                                                  Object componentKey,
119                                                  Class<T> componentImplementation, Parameter... parameters) {
120        AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.CDI);
121        return new ConstructorInjection().createComponentAdapter(componentMonitor,
122                                                                        lifecycleStrategy,
123                                                                        componentProperties,
124                                                                        componentKey,
125                                                                        componentImplementation,
126                                                                        parameters);
127    }
128
129    private <T> ComponentAdapter<T> setterInjectionAdapter(Properties componentProperties,
130                                                   ComponentMonitor componentMonitor,
131                                                   LifecycleStrategy lifecycleStrategy,
132                                                   Object componentKey,
133                                                   Class<T> componentImplementation,
134                                                   ComponentAdapter<T> componentAdapter,
135                                                   Parameter... parameters) {
136        if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.SDI)) {
137            componentAdapter = new SetterInjection().createComponentAdapter(componentMonitor, lifecycleStrategy,
138                                                                                                    componentProperties,
139                                                                                                    componentKey,
140                                                                                                    componentImplementation,
141                                                                                                    parameters);
142        }
143        return componentAdapter;
144    }
145
146    private <T> ComponentAdapter<T> methodInjectionAdapter(Properties componentProperties,
147                                                   ComponentMonitor componentMonitor,
148                                                   LifecycleStrategy lifecycleStrategy,
149                                                   Object componentKey,
150                                                   Class<T> componentImplementation,
151                                                   ComponentAdapter<T> componentAdapter,
152                                                   Parameter... parameters) {
153        if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.METHOD_INJECTION)) {
154            componentAdapter = new MethodInjection().createComponentAdapter(componentMonitor, lifecycleStrategy,
155                                                                                                    componentProperties,
156                                                                                                    componentKey,
157                                                                                                    componentImplementation,
158                                                                                                    parameters);
159        }
160        return componentAdapter;
161    }
162
163
164    private <T> ComponentAdapter<T> methodAnnotatedInjectionAdapter(Class<T> componentImplementation,
165                                                             ComponentMonitor componentMonitor,
166                                                             LifecycleStrategy lifecycleStrategy,
167                                                             Properties componentProperties,
168                                                             Object componentKey,
169                                                             ComponentAdapter<T> componentAdapter,
170                                                             Parameter... parameters) {
171        if (injectionMethodAnnotated(componentImplementation)) {
172            componentAdapter =
173                new AnnotatedMethodInjection().createComponentAdapter(componentMonitor,
174                                                                              lifecycleStrategy,
175                                                                              componentProperties,
176                                                                              componentKey,
177                                                                              componentImplementation,
178                                                                              parameters);
179        }
180        return componentAdapter;
181    }
182
183    private <T> ComponentAdapter<T> fieldAnnotatedInjectionAdapter(Class<T> componentImplementation,
184                                 ComponentMonitor componentMonitor,
185                                 LifecycleStrategy lifecycleStrategy,
186                                 Properties componentProperties,
187                                 Object componentKey, ComponentAdapter<T> componentAdapter, Parameter... parameters) {
188        if (injectionFieldAnnotated(componentImplementation)) {
189             componentAdapter = new AnnotatedFieldInjection().createComponentAdapter(componentMonitor,
190                                                                             lifecycleStrategy,
191                                                                             componentProperties,
192                                                                             componentKey,
193                                                                             componentImplementation,
194                                                                             parameters);
195        }
196        return componentAdapter;
197    }
198
199    private boolean injectionMethodAnnotated(final Class<?> componentImplementation) {
200        return (Boolean) AccessController.doPrivileged(new PrivilegedAction<Object>() {
201            @SuppressWarnings("synthetic-access")
202            public Object run() {
203                return injectionAnnotated(componentImplementation.getDeclaredMethods());
204            }
205        });
206    }
207
208    private boolean injectionFieldAnnotated(final Class<?> componentImplementation) {
209        return (Boolean) AccessController.doPrivileged(new PrivilegedAction<Object>() {
210            @SuppressWarnings("synthetic-access")
211            public Object run() {
212                if (componentImplementation.isInterface()) {
213                    return false;
214                }
215                Class impl = componentImplementation;
216                while (impl != Object.class) {
217                    boolean injAnnotated = injectionAnnotated(impl.getDeclaredFields());
218                    if (injAnnotated) {
219                        return true;
220                    }
221                    impl = impl.getSuperclass();
222                }
223                return false;
224            }
225        });
226    }
227    
228    private boolean injectionAnnotated(AccessibleObject[] objects) {
229        for (AccessibleObject object : objects) {
230            if (object.getAnnotation(Inject.class) != null) {
231                return true;
232            }
233        }
234        return false;
235    }
236
237}