Package org.picocontainer.defaults

Source Code of org.picocontainer.defaults.BasicComponentParameter

/*****************************************************************************
* Copyright (C) PicoContainer Organization. All rights reserved.            *
* ------------------------------------------------------------------------- *
* The software in this package is published under the terms of the BSD      *
* style license a copy of which has been included with this distribution in *
* the LICENSE.txt file.                                                     *
*                                                                           *
* Original code by                                                          *
*****************************************************************************/
package org.picocontainer.defaults;

import org.picocontainer.ComponentAdapter;
import org.picocontainer.Parameter;
import org.picocontainer.PicoContainer;
import org.picocontainer.PicoInstantiationException;
import org.picocontainer.PicoIntrospectionException;
import org.picocontainer.PicoVisitor;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Iterator;

/**
* A BasicComponentParameter should be used to pass in a particular component as argument to a
* different component's constructor. This is particularly useful in cases where several
* components of the same type have been registered, but with a different key. Passing a
* ComponentParameter as a parameter when registering a component will give PicoContainer a hint
* about what other component to use in the constructor. This Parameter will never resolve
* against a collecting type, that is not directly registered in the PicoContainer itself.
*
* @author Jon Tirsén
* @author Aslak Hellesøy
* @author Jörg Schaible
* @author Thomas Heller
* @version $Revision: 1944 $
*/
public class BasicComponentParameter
        implements Parameter, Serializable {

    /**
     * <code>BASIC_DEFAULT</code> is an instance of BasicComponentParameter using the default constructor.
     */
    public static final BasicComponentParameter BASIC_DEFAULT = new BasicComponentParameter();

    private Object componentKey;

    /**
     * Expect a parameter matching a component of a specific key.
     *
     * @param componentKey the key of the desired component
     */
    public BasicComponentParameter(Object componentKey) {
        this.componentKey = componentKey;
    }

    /**
     * Expect any paramter of the appropriate type.
     */
    public BasicComponentParameter() {
    }

    /**
     * Check wether the given Parameter can be statisfied by the container.
     *
     * @return <code>true</code> if the Parameter can be verified.
     * @see org.picocontainer.Parameter#isResolvable(org.picocontainer.PicoContainer,
     *           org.picocontainer.ComponentAdapter, java.lang.Class)
     */
    public boolean isResolvable(PicoContainer container, ComponentAdapter adapter, Class expectedType) {
        return resolveAdapter(container, adapter, expectedType) != null;
    }

    public Object resolveInstance(PicoContainer container, ComponentAdapter adapter, Class expectedType)
            throws PicoInstantiationException {
        final ComponentAdapter componentAdapter = resolveAdapter(container, adapter, expectedType);
        if (componentAdapter != null) {
            return container.getComponentInstance(componentAdapter.getComponentKey());
        }
        return null;
    }

    public void verify(PicoContainer container, ComponentAdapter adapter, Class expectedType) throws PicoIntrospectionException {
        final ComponentAdapter componentAdapter = resolveAdapter(container, adapter, expectedType);
        if (componentAdapter == null) {
            final HashSet set = new HashSet();
            set.add(Arrays.asList(new Class[] {expectedType}));
            throw new UnsatisfiableDependenciesException(adapter, set);
        }
        componentAdapter.verify(container);
    }

    /**
     * Visit the current {@link Parameter}.
     *
     * @see org.picocontainer.Parameter#accept(org.picocontainer.PicoVisitor)
     */
    public void accept(final PicoVisitor visitor) {
        visitor.visitParameter(this);
    }

    private ComponentAdapter resolveAdapter(PicoContainer container, ComponentAdapter adapter, Class expectedType) {

        final ComponentAdapter result = getTargetAdapter(container, expectedType,adapter);
        if (result == null) {
            return null;
        }

        if (!expectedType.isAssignableFrom(result.getComponentImplementation())) {
            // check for primitive value
            if (expectedType.isPrimitive()) {
                try {
                    final Field field = result.getComponentImplementation().getField("TYPE");
                    final Class type = (Class) field.get(result.getComponentInstance(null));
                    if (expectedType.isAssignableFrom(type)) {
                        return result;
                    }
                } catch (NoSuchFieldException e) {
                } catch (IllegalArgumentException e) {
                } catch (IllegalAccessException e) {
                } catch (ClassCastException e) {
                }
            }
            return null;
        }
        return result;
    }

    private ComponentAdapter getTargetAdapter(PicoContainer container, Class expectedType, ComponentAdapter excludeAdapter) {
        if (componentKey != null) {
            // key tells us where to look so we follow
            return container.getComponentAdapter(componentKey);
        } else if(excludeAdapter == null) {
            return container.getComponentAdapterOfType(expectedType);
        } else {
            Object excludeKey = excludeAdapter.getComponentKey();
            ComponentAdapter byKey = container.getComponentAdapter(expectedType);
            if(byKey != null ) {
                if( byKey.getComponentKey().equals(excludeKey)) {
                    return null;
                }
                return byKey;
            }
            List found = container.getComponentAdaptersOfType(expectedType);
            ComponentAdapter exclude = null;
            ComponentAdapter work;
            for(Iterator iterator = found.iterator(); iterator.hasNext();) {
                work = (ComponentAdapter) iterator.next();
                if( work.getComponentKey().equals(excludeKey)) {
                    exclude = work;
                }
            }
            found.remove(exclude);
            if(found.size() == 0) {
                if( container.getParent() != null) {
                    return container.getParent().getComponentAdapterOfType(expectedType);
                } else {
                    return null;
                }
            } else if(found.size() == 1) {
                return (ComponentAdapter)found.get(0);
            } else {
                Class[] foundClasses = new Class[found.size()];
                for (int i = 0; i < foundClasses.length; i++) {
                    foundClasses[i] = ((ComponentAdapter) found.get(i)).getComponentImplementation();
                }
                throw new AmbiguousComponentResolutionException(expectedType, foundClasses);
            }
        }
    }
}
TOP

Related Classes of org.picocontainer.defaults.BasicComponentParameter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.