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.gems.constraints;
010
011import org.picocontainer.Behavior;
012import org.picocontainer.ComponentAdapter;
013import org.picocontainer.LifecycleStrategy;
014import org.picocontainer.NameBinding;
015import org.picocontainer.Parameter;
016import org.picocontainer.PicoCompositionException;
017import org.picocontainer.PicoContainer;
018import org.picocontainer.adapters.InstanceAdapter;
019import org.picocontainer.injectors.AbstractInjector;
020import org.picocontainer.parameters.CollectionComponentParameter;
021
022import java.lang.annotation.Annotation;
023import java.lang.reflect.Array;
024import java.lang.reflect.Type;
025import java.util.Collection;
026import java.util.Map;
027
028/**
029 * Base class for parameter constraints.
030 *
031 * @author Nick Sieger
032 */
033public abstract class AbstractConstraint extends CollectionComponentParameter implements Constraint {
034
035    /** Construct an AbstractContraint. */
036    protected AbstractConstraint() {
037        super(false);
038    }
039
040    @Override
041        public Resolver resolve(final PicoContainer container,
042                         final ComponentAdapter<?> forAdapter,
043                         ComponentAdapter<?> injecteeAdapter, final Type expectedType,
044                         final NameBinding expectedNameBinding, final boolean useNames, final Annotation binding) throws PicoCompositionException {
045        final Resolver resolver;
046        return new Parameter.DelegateResolver(super.resolve(container, forAdapter,
047                null, getArrayType((Class) expectedType), expectedNameBinding, useNames, binding)) {
048            @Override
049            public Object resolveInstance() {
050                final Object[] array = (Object[]) super.resolveInstance();
051                if (array.length == 1) {
052                    return array[0];
053                }
054                return null;
055            }
056        };
057    }
058
059    @Override
060        public void verify(final PicoContainer container,
061                       final ComponentAdapter<?> adapter,
062                       final Type expectedType,
063                       final NameBinding expectedNameBinding, final boolean useNames, final Annotation binding) throws PicoCompositionException {
064        super.verify(container, adapter, getArrayType((Class) expectedType), expectedNameBinding, useNames, binding);
065    }
066
067    @Override
068        public abstract boolean evaluate(ComponentAdapter adapter);
069
070    @Override
071        protected Map<Object, ComponentAdapter<?>> getMatchingComponentAdapters(final PicoContainer container,
072                                                                            final ComponentAdapter adapter,
073                                                                            final Class keyType,
074                                                                            final Class valueType) {
075        final Map<Object, ComponentAdapter<?>> map =
076            super.getMatchingComponentAdapters(container, adapter, keyType, valueType);
077        if (map.size() > 1) {
078            String[] foundStrings = makeFoundAmbiguousStrings(map.values());
079            throw new AbstractInjector.AmbiguousComponentResolutionException(valueType, foundStrings);
080        }
081        return map;
082    }
083
084    public static String[] makeFoundAmbiguousStrings(Collection<ComponentAdapter<?>> found) {
085        String[] foundStrings = new String[found.size()];
086        int ix = 0;
087        for (ComponentAdapter<?> f : found) {
088            while (f instanceof Behavior || (f instanceof LifecycleStrategy && !(f instanceof InstanceAdapter))) {
089                f = f.getDelegate();
090            }
091            foundStrings[ix++] = f.toString();
092        }
093        return foundStrings;
094    }
095
096
097    private Type getArrayType(final Class expectedType) {
098        return Array.newInstance(expectedType, 0).getClass();
099    }
100}