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     *****************************************************************************/
009    package org.picocontainer.injectors;
010    
011    import org.picocontainer.*;
012    import org.picocontainer.behaviors.Cached;
013    import org.picocontainer.lifecycle.NullLifecycleStrategy;
014    
015    import java.lang.reflect.Method;
016    import java.lang.reflect.Type;
017    import java.util.Properties;
018    
019    /**
020     * Providers are a type of Injector that can participate in Injection via a custom method.
021     *
022     * Implementers of this class must implement a single method called provide.  That method must return
023     * the component type intended to be provided.  The method can accept parameters that PicoContainer
024     * will satisfy.
025     */
026    public class ProviderAdapter implements org.picocontainer.Injector, Provider, LifecycleStrategy {
027    
028        private final Object provider;
029        private final Method provideMethod;
030        private final Class key;
031        private Properties properties;
032        private LifecycleStrategy lifecycleStrategy;
033    
034        protected ProviderAdapter() {
035            provider = this;
036            provideMethod = getProvideMethod(this.getClass());
037            key = provideMethod.getReturnType();
038            setUseNames(useNames());
039        }
040    
041        public ProviderAdapter(LifecycleStrategy lifecycleStrategy, Object provider) {
042            this(lifecycleStrategy, provider, false);
043        }
044    
045        public ProviderAdapter(Object provider) {
046            this(new NullLifecycleStrategy(), provider, false);
047        }
048    
049        public ProviderAdapter(Object provider, boolean useNames) {
050            this(new NullLifecycleStrategy(), provider, useNames);
051        }
052    
053        public ProviderAdapter(LifecycleStrategy lifecycleStrategy, Object provider, boolean useNames) {
054            this.lifecycleStrategy = lifecycleStrategy;
055            this.provider = provider;
056            provideMethod = getProvideMethod(provider.getClass());
057            key = provideMethod.getReturnType();
058            setUseNames(useNames);
059        }
060    
061    
062        private void setUseNames(boolean b) {
063            if (b) {
064                properties = Characteristics.USE_NAMES;
065            } else {
066                properties = Characteristics.NONE;
067            }
068        }
069    
070        protected boolean useNames() {
071            return false;
072        }
073    
074        public Object decorateComponentInstance(PicoContainer container, Type into, Object instance) {
075            return null;
076        }
077    
078        public Object getComponentKey() {
079            return key;
080        }
081    
082        public Class getComponentImplementation() {
083            return key;
084        }
085    
086        @Deprecated
087        public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
088            return getComponentInstance(container, NOTHING.class);
089        }
090    
091        public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
092            return new Reinjector(container).reinject(key, provider.getClass(), provider, properties, new MethodInjection(provideMethod));
093        }
094    
095        public static Method getProvideMethod(Class clazz) {
096            Method provideMethod = null;
097            // TODO doPrivileged
098            for (Method method : clazz.getDeclaredMethods()) {
099                if (method.getName().equals("provide")) {
100                    if (provideMethod != null) {
101                        throw newProviderMethodException("only one");
102                    }
103                    provideMethod = method;
104                }
105            }
106            if (provideMethod == null) {
107                throw newProviderMethodException("a");
108            }
109            if (provideMethod.getReturnType() == void.class) {
110                throw newProviderMethodException("a non void returning");
111            }
112            return provideMethod;
113        }
114    
115        private static PicoCompositionException newProviderMethodException(String str) {
116            return new PicoCompositionException("There must be "+ str +" method named 'provide' in the AbstractProvider implementation");
117        }
118    
119        public void verify(PicoContainer container) throws PicoCompositionException {
120        }
121    
122        public void accept(PicoVisitor visitor) {
123        }
124    
125        public ComponentAdapter getDelegate() {
126            return null;
127        }
128    
129        public ComponentAdapter findAdapterOfType(Class adapterType) {
130            return null;
131        }
132    
133        public String getDescriptor() {
134            return "ProviderAdapter";
135        }
136    
137        public void start(Object component) {
138            lifecycleStrategy.start(component);
139        }
140    
141        public void stop(Object component) {
142            lifecycleStrategy.stop(component);
143        }
144    
145        public void dispose(Object component) {
146            lifecycleStrategy.dispose(component);
147        }
148    
149    
150        public boolean hasLifecycle(Class<?> type) {
151            return lifecycleStrategy.hasLifecycle(type);
152        }
153    
154        public boolean isLazy(ComponentAdapter<?> adapter) {
155            return lifecycleStrategy.isLazy(adapter);
156        }
157    }