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 org.picocontainer.ComponentAdapter;
014    import org.picocontainer.ComponentMonitor;
015    import org.picocontainer.Parameter;
016    import org.picocontainer.PicoCompositionException;
017    import org.picocontainer.Characteristics;
018    import org.picocontainer.LifecycleStrategy;
019    import org.picocontainer.InjectionFactory;
020    import org.picocontainer.behaviors.AbstractBehaviorFactory;
021    import org.picocontainer.injectors.MethodInjection;
022    import org.picocontainer.annotations.Inject;
023    
024    import java.io.Serializable;
025    import java.lang.reflect.Field;
026    import java.lang.reflect.Method;
027    import java.util.Properties;
028    
029    /**
030     * Creates instances Injectors, depending on whether the component is the presence of Annotations and characteristics.
031     *
032     * @author Paul Hammant
033     */
034    public class AdaptiveInjection implements InjectionFactory, Serializable {
035    
036        public ComponentAdapter createComponentAdapter(ComponentMonitor componentMonitor,
037                                                       LifecycleStrategy lifecycleStrategy,
038                                                       Properties componentProperties,
039                                                       Object componentKey,
040                                                       Class componentImplementation,
041                                                       Parameter... parameters) throws PicoCompositionException {
042            ComponentAdapter componentAdapter = null;
043            componentAdapter = makeIfFieldAnnotationInjection(componentImplementation,
044                                   componentMonitor,
045                                   lifecycleStrategy,
046                                   componentProperties,
047                                   componentKey,
048                                   componentAdapter,
049                                   parameters);
050    
051            if (componentAdapter != null) {
052                return componentAdapter;
053            }
054    
055    
056            componentAdapter = makeIfMethodAnnotationInjection(componentImplementation,
057                                                               componentMonitor,
058                                                               lifecycleStrategy,
059                                                               componentProperties,
060                                                               componentKey,
061                                                               componentAdapter,
062                                                               parameters);
063    
064            if (componentAdapter != null) {
065                return componentAdapter;
066            }
067    
068            componentAdapter = makeIfSetterInjection(componentProperties,
069                                                     componentMonitor,
070                                                     lifecycleStrategy,
071                                                     componentKey,
072                                                     componentImplementation,
073                                                     componentAdapter,
074                                                     parameters);
075    
076            if (componentAdapter != null) {
077                return componentAdapter;
078            }
079    
080            componentAdapter = makeIfMethodInjection(componentProperties,
081                                                     componentMonitor,
082                                                     lifecycleStrategy,
083                                                     componentKey,
084                                                     componentImplementation,
085                                                     componentAdapter,
086                                                     parameters);
087    
088            if (componentAdapter != null) {
089                return componentAdapter;
090            }
091    
092    
093            return makeDefaultInjection(componentProperties,
094                                        componentMonitor,
095                                        lifecycleStrategy,
096                                        componentKey,
097                                        componentImplementation,
098                                        parameters);
099        }
100    
101        protected ComponentAdapter makeDefaultInjection(Properties componentProperties,
102                                                      ComponentMonitor componentMonitor,
103                                                      LifecycleStrategy lifecycleStrategy,
104                                                      Object componentKey,
105                                                      Class componentImplementation, Parameter... parameters) {
106            AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.CDI);
107            return new ConstructorInjection().createComponentAdapter(componentMonitor,
108                                                                            lifecycleStrategy,
109                                                                            componentProperties,
110                                                                            componentKey,
111                                                                            componentImplementation,
112                                                                            parameters);
113        }
114    
115        protected ComponentAdapter makeIfSetterInjection(Properties componentProperties,
116                                                       ComponentMonitor componentMonitor,
117                                                       LifecycleStrategy lifecycleStrategy,
118                                                       Object componentKey,
119                                                       Class componentImplementation,
120                                                       ComponentAdapter componentAdapter,
121                                                       Parameter... parameters) {
122            if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.SDI)) {
123                componentAdapter = new SetterInjection().createComponentAdapter(componentMonitor, lifecycleStrategy,
124                                                                                                        componentProperties,
125                                                                                                        componentKey,
126                                                                                                        componentImplementation,
127                                                                                                        parameters);
128            }
129            return componentAdapter;
130        }
131    
132        protected ComponentAdapter makeIfMethodInjection(Properties componentProperties,
133                                                       ComponentMonitor componentMonitor,
134                                                       LifecycleStrategy lifecycleStrategy,
135                                                       Object componentKey,
136                                                       Class componentImplementation,
137                                                       ComponentAdapter componentAdapter,
138                                                       Parameter... parameters) {
139            if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.METHOD_INJECTION)) {
140                componentAdapter = new MethodInjection().createComponentAdapter(componentMonitor, lifecycleStrategy,
141                                                                                                        componentProperties,
142                                                                                                        componentKey,
143                                                                                                        componentImplementation,
144                                                                                                        parameters);
145            }
146            return componentAdapter;
147        }
148    
149    
150        protected ComponentAdapter makeIfMethodAnnotationInjection(Class componentImplementation,
151                                                                 ComponentMonitor componentMonitor,
152                                                                 LifecycleStrategy lifecycleStrategy,
153                                                                 Properties componentProperties,
154                                                                 Object componentKey,
155                                                                 ComponentAdapter componentAdapter,
156                                                                 Parameter... parameters) {
157            if (isMethodAnnotationInjection(componentImplementation)) {
158                componentAdapter =
159                    new AnnotatedMethodInjection().createComponentAdapter(componentMonitor,
160                                                                                  lifecycleStrategy,
161                                                                                  componentProperties,
162                                                                                  componentKey,
163                                                                                  componentImplementation,
164                                                                                  parameters);
165            }
166            return componentAdapter;
167        }
168    
169        protected ComponentAdapter makeIfFieldAnnotationInjection(Class componentImplementation,
170                                     ComponentMonitor componentMonitor,
171                                     LifecycleStrategy lifecycleStrategy,
172                                     Properties componentProperties,
173                                     Object componentKey, ComponentAdapter componentAdapter, Parameter... parameters)
174        {
175            if (isFieldAnnotationInjection(componentImplementation)) {
176                 componentAdapter =
177                    new AnnotatedFieldInjection().createComponentAdapter(componentMonitor,
178                                                                                 lifecycleStrategy,
179                                                                                 componentProperties,
180                                                                                 componentKey,
181                                                                                 componentImplementation,
182                                                                                 parameters);
183            }
184            return componentAdapter;
185        }
186    
187        protected boolean isMethodAnnotationInjection(Class componentImplementation) {
188            Method[] methods = componentImplementation.getDeclaredMethods();
189            for (Method method : methods) {
190                if (method.getAnnotation(Inject.class) != null) {
191                    return true;
192                }
193            }
194            return false;
195        }
196    
197        protected boolean isFieldAnnotationInjection(Class componentImplementation) {
198            Field[] fields = componentImplementation.getDeclaredFields();
199            for (Field field : fields) {
200                if (field.getAnnotation(Inject.class) != null) {
201                    return true;
202                }
203            }
204            return false;
205        }
206    
207    }