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 *****************************************************************************/
009package org.picocontainer.injectors;
010
011import org.picocontainer.Characteristics;
012import org.picocontainer.ComponentAdapter;
013import org.picocontainer.LifecycleStrategy;
014import org.picocontainer.PicoCompositionException;
015import org.picocontainer.PicoContainer;
016import org.picocontainer.PicoVisitor;
017import org.picocontainer.lifecycle.NullLifecycleStrategy;
018
019import java.lang.reflect.Method;
020import java.lang.reflect.Type;
021import 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 */
030public 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}