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