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.security.AccessController;
015    import java.security.PrivilegedAction;
016    import java.util.Properties;
017    import org.picocontainer.Characteristics;
018    import org.picocontainer.ComponentAdapter;
019    import org.picocontainer.ComponentMonitor;
020    import org.picocontainer.LifecycleStrategy;
021    import org.picocontainer.Parameter;
022    import org.picocontainer.PicoCompositionException;
023    import org.picocontainer.annotations.Inject;
024    import 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")
046    public 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    }