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øy
034 * @author Jon Tirsé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 }