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 * Original code by                                                          *
009 *****************************************************************************/
010package org.picocontainer.adapters;
011
012import org.picocontainer.ComponentMonitor;
013import org.picocontainer.PicoVisitor;
014import org.picocontainer.ComponentAdapter;
015import org.picocontainer.ComponentMonitorStrategy;
016import org.picocontainer.PicoContainer;
017import org.picocontainer.PicoCompositionException;
018import org.picocontainer.injectors.ProviderAdapter;
019import org.picocontainer.injectors.Provider;
020import org.picocontainer.monitors.AbstractComponentMonitor;
021import org.picocontainer.monitors.NullComponentMonitor;
022
023import java.io.Serializable;
024
025/**
026 * Base class for a ComponentAdapter with general functionality.
027 * This implementation provides basic checks for a healthy implementation of a ComponentAdapter.
028 * It does not allow to use <code>null</code> for the component key or the implementation,
029 * ensures that the implementation is a concrete class and that the key is assignable from the
030 * implementation if the key represents a type.
031 *
032 * @author Paul Hammant
033 * @author Aslak Helles&oslash;y
034 * @author Jon Tirs&eacute;n
035 */
036public abstract class AbstractAdapter<T> implements ComponentAdapter<T>, ComponentMonitorStrategy, Serializable {
037    private Object componentKey;
038    private Class<T> componentImplementation;
039    private ComponentMonitor componentMonitor;
040
041    /**
042     * Constructs a new ComponentAdapter for the given key and implementation.
043     * @param componentKey the search key for this implementation
044     * @param componentImplementation the concrete implementation
045     */
046    public AbstractAdapter(Object componentKey, Class componentImplementation) {
047        this(componentKey, componentImplementation, new AbstractComponentMonitor());
048        this.componentMonitor = new NullComponentMonitor();
049    }
050
051    /**
052     * Constructs a new ComponentAdapter for the given key and implementation.
053     * @param componentKey the search key for this implementation
054     * @param componentImplementation the concrete implementation
055     * @param monitor the component monitor used by this ComponentAdapter
056     */
057    public AbstractAdapter(Object componentKey, Class componentImplementation, ComponentMonitor monitor) {
058        if (monitor == null) {
059            throw new NullPointerException("ComponentMonitor==null");
060        }
061        this.componentMonitor = monitor;
062        if (componentImplementation == null) {
063            throw new NullPointerException("componentImplementation");
064        }
065        this.componentKey = componentKey;
066        this.componentImplementation = componentImplementation;
067        checkTypeCompatibility();
068    }
069
070    /**
071     * {@inheritDoc}
072     * @see org.picocontainer.ComponentAdapter#getComponentKey()
073     */
074    public Object getComponentKey() {
075        if (componentKey == null) {
076            throw new NullPointerException("componentKey");
077        }
078        return componentKey;
079    }
080
081    /**
082     * {@inheritDoc}
083     * @see org.picocontainer.ComponentAdapter#getComponentImplementation()
084     */
085    public Class<? extends T> getComponentImplementation() {
086        return componentImplementation;
087    }
088
089    protected void checkTypeCompatibility() {
090        if (componentKey instanceof Class) {
091            Class<?> componentType = (Class) componentKey;
092            if (Provider.class.isAssignableFrom(componentImplementation)) {
093                if (!componentType.isAssignableFrom(ProviderAdapter.getProvideMethod(componentImplementation).getReturnType())) {
094                    throw newCCE(componentType);
095                }
096            } else {
097                if (!componentType.isAssignableFrom(componentImplementation)) {
098                    throw newCCE(componentType);
099                }
100            }
101        }
102    }
103
104    private ClassCastException newCCE(Class<?> componentType) {
105        return new ClassCastException(componentImplementation.getName() + " is not a " + componentType.getName());
106    }
107
108    public T getComponentInstance(PicoContainer container) throws PicoCompositionException {
109        return getComponentInstance(container, null);
110    }
111
112    /**
113     * @return Returns the ComponentAdapter's class name and the component's key.
114     * @see java.lang.Object#toString()
115     */
116    public String toString() {
117        return getDescriptor() + getComponentKey();
118    }
119
120    public void accept(PicoVisitor visitor) {
121        visitor.visitComponentAdapter(this);
122    }
123
124    public void changeMonitor(ComponentMonitor monitor) {
125        this.componentMonitor = monitor;
126    }
127
128    /**
129     * Returns the monitor currently used
130     * @return The ComponentMonitor currently used
131     */
132    public ComponentMonitor currentMonitor(){
133        return componentMonitor;
134    }
135
136    public final ComponentAdapter<T> getDelegate() {
137        return null;
138    }
139
140    public final <U extends ComponentAdapter> U findAdapterOfType(Class<U> adapterType) {
141        if (adapterType.isAssignableFrom(this.getClass())) {
142            return (U) this;
143        } else if (getDelegate() != null) {
144            return getDelegate().findAdapterOfType(adapterType);
145        }
146        return null;
147    }
148
149
150}