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}