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