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