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