You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by zo...@apache.org on 2011/02/27 22:05:20 UTC

svn commit: r1075147 [10/23] - in /aries/tags/blueprint-0.3: ./ blueprint-annotation-api/ blueprint-annotation-api/src/ blueprint-annotation-api/src/main/ blueprint-annotation-api/src/main/java/ blueprint-annotation-api/src/main/java/org/ blueprint-ann...

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,446 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.blueprint.container;
+
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+import java.math.BigInteger;
+import java.math.BigDecimal;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.apache.aries.blueprint.di.MapRecipe;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+
+import static org.apache.aries.blueprint.utils.ReflectionUtils.getRealCause;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.container.Converter;
+
+/**
+ * Implementation of the Converter.
+ *
+ * This object contains all the registered Converters which can be registered
+ * by using {@link #registerConverter(Converter)}
+ * and unregistered using {@link #unregisterConverter(Converter)}.
+ *
+ * Each {@link org.osgi.service.blueprint.container.BlueprintContainer} has its own AggregateConverter
+ * used to register converters defined by the related blueprint bundle.
+ *
+ * @version $Rev: 990789 $, $Date: 2010-08-30 13:42:03 +0100 (Mon, 30 Aug 2010) $
+ */
+public class AggregateConverter implements Converter {
+
+    /**
+     * Objects implementing this interface will bypass the default conversion rules
+     * and be called directly to transform into the expected type.
+     */
+    public static interface Convertible {
+
+        Object convert(ReifiedType type) throws Exception;
+    }
+
+    private static class ConversionResult {
+
+        public final Converter converter;
+        public final Object value;
+
+        public ConversionResult(Converter converter, Object value) {
+            this.converter = converter;
+            this.value = value;
+        }
+    }
+
+    private ExtendedBlueprintContainer blueprintContainer;
+    private List<Converter> converters = new ArrayList<Converter>();
+
+    public AggregateConverter(ExtendedBlueprintContainer blueprintContainer) {
+        this.blueprintContainer = blueprintContainer;
+    }
+
+    public void registerConverter(Converter converter) {
+        converters.add(converter);
+    }
+
+    public void unregisterConverter(Converter converter) {
+        converters.remove(converter);
+    }
+
+    public boolean canConvert(final Object fromValue, final ReifiedType toType) {
+        if (fromValue == null) {
+            return true;
+        }
+        if (isAssignable(fromValue, toType)) {
+            return true;
+        }
+        
+        boolean canConvert = false;
+        AccessControlContext acc = blueprintContainer.getAccessControlContext();
+        if (acc == null) {
+            canConvert = canConvertWithConverters(fromValue, toType);
+        } else {
+            canConvert = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return canConvertWithConverters(fromValue, toType);
+                }            
+            }, acc);
+        }
+        if (canConvert) {
+            return true;
+        }
+        
+        // TODO implement better logic ?!
+        try {
+            convert(fromValue, toType);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    public Object convert(final Object fromValue, final ReifiedType type) throws Exception {
+        // Discard null values
+        if (fromValue == null) {
+            return null;
+        }
+        // First convert service proxies
+        if (fromValue instanceof Convertible) {
+            return ((Convertible) fromValue).convert(type);
+        }
+        // If the object is an instance of the type, just return it
+        if (isAssignable(fromValue, type)) {
+            return fromValue;
+        }
+        ConversionResult result = null;
+        AccessControlContext acc = blueprintContainer.getAccessControlContext();
+        if (acc == null) {
+            result = convertWithConverters(fromValue, type);
+        } else {
+            result = AccessController.doPrivileged(new PrivilegedExceptionAction<ConversionResult>() {
+                public ConversionResult run() throws Exception {
+                    return convertWithConverters(fromValue, type);
+                }            
+            }, acc);
+        }
+        if (result == null) {
+            if (fromValue instanceof Number && Number.class.isAssignableFrom(unwrap(toClass(type)))) {
+                return convertToNumber((Number) fromValue, toClass(type));
+            } else if (fromValue instanceof String) {
+                return convertFromString((String) fromValue, toClass(type), blueprintContainer);
+            } else if (toClass(type).isArray() && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+                return convertToArray(fromValue, type);
+            } else if (Map.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+                return convertToMap(fromValue, type);
+            } else if (Dictionary.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+                return convertToDictionary(fromValue, type);
+            } else if (Collection.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+                return convertToCollection(fromValue, type);
+            } else {
+                throw new Exception("Unable to convert value " + fromValue + " to type " + type);
+            }
+        }
+        return result.value;
+    }
+
+    private Converter selectMatchingConverter(Object source, ReifiedType type) {
+        for (Converter converter : converters) {
+            if (converter.canConvert(source, type)) {
+                return converter;
+            }
+        }
+        return null;
+    }
+
+    private boolean canConvertWithConverters(Object source, ReifiedType type) {
+        return selectMatchingConverter(source,type) != null;
+    }
+    
+    private ConversionResult convertWithConverters(Object source, ReifiedType type) throws Exception {
+
+        Converter converter = selectMatchingConverter(source,type);
+
+        if (converter == null)  return null;
+
+        Object value = converter.convert(source, type);
+        return new ConversionResult(converter,value);
+    }
+    
+    public Object convertToNumber(Number value, Class toType) throws Exception {
+        toType = unwrap(toType);
+        if (AtomicInteger.class == toType) {
+            return new AtomicInteger((Integer) convertToNumber(value, Integer.class));
+        } else if (AtomicLong.class == toType) {
+            return new AtomicLong((Long) convertToNumber(value, Long.class));
+        } else if (Integer.class == toType) {
+            return value.intValue();
+        } else if (Short.class == toType) {
+            return value.shortValue();
+        } else if (Long.class == toType) {
+            return value.longValue();
+        } else if (Float.class == toType) {
+            return value.floatValue();
+        } else if (Double.class == toType) {
+            return value.doubleValue();
+        } else if (Byte.class == toType) {
+            return value.byteValue();
+        } else if (BigInteger.class == toType) {
+            return new BigInteger(value.toString());
+        } else if (BigDecimal.class == toType) {
+            return new BigDecimal(value.toString());
+        } else {
+            throw new Exception("Unable to convert number " + value + " to " + toType);
+        }
+    }
+
+    public Object convertFromString(String value, Class toType, Object loader) throws Exception {
+        toType = unwrap(toType);
+        if (ReifiedType.class == toType) {
+            try {
+                return GenericType.parse(value, loader);
+            } catch (ClassNotFoundException e) {
+                throw new Exception("Unable to convert", e);
+            }
+        } else if (Class.class == toType) {
+            try {
+                return GenericType.parse(value, loader).getRawClass();
+            } catch (ClassNotFoundException e) {
+                throw new Exception("Unable to convert", e);
+            }
+        } else if (Locale.class == toType) {
+            String[] tokens = value.split("_");
+            if (tokens.length == 1) {
+                return new Locale(tokens[0]);
+            } else if (tokens.length == 2) {
+                return new Locale(tokens[0], tokens[1]);
+            } else if (tokens.length == 3) {
+                return new Locale(tokens[0], tokens[1], tokens[2]);
+            } else {
+                throw new Exception("Invalid locale string:" + value);
+            }
+        } else if (Pattern.class == toType) {
+            return Pattern.compile(value);
+        } else if (Properties.class == toType) {
+            Properties props = new Properties();
+            ByteArrayInputStream in = new ByteArrayInputStream(value.getBytes("UTF8"));
+            props.load(in);
+            return props;
+        } else if (Boolean.class == toType) {
+            if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)) {
+                return Boolean.TRUE;
+            } else if ("no".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "off".equalsIgnoreCase(value)) {
+                return Boolean.FALSE;
+            } else {
+                throw new RuntimeException("Invalid boolean value: " + value);
+            }
+        } else if (Integer.class == toType) {
+            return Integer.valueOf(value);
+        } else if (Short.class == toType) {
+            return Short.valueOf(value);
+        } else if (Long.class == toType) {
+            return Long.valueOf(value);
+        } else if (Float.class == toType) {
+            return Float.valueOf(value);
+        } else if (Double.class == toType) {
+            return Double.valueOf(value);
+        } else if (Character.class == toType) {
+            if (value.length() == 6 && value.startsWith("\\u")) {
+                int code = Integer.parseInt(value.substring(2), 16);
+                return (char)code;
+            } else if (value.length() == 1) {
+                return value.charAt(0);
+            } else {
+                throw new Exception("Invalid value for character type: " + value);
+            }
+        } else if (Byte.class == toType) {
+            return Byte.valueOf(value);
+        } else if (Enum.class.isAssignableFrom(toType)) {
+            return Enum.valueOf((Class<Enum>) toType, value);
+        } else {
+            return createObject(value, toType);
+        }
+    }
+
+    private Object createObject(String value, Class type) throws Exception {
+        if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
+            throw new Exception("Unable to convert value " + value + " to type " + type + ". Type " + type + " is an interface or an abstract class");
+        }
+        Constructor constructor = null;
+        try {
+            constructor = type.getConstructor(String.class);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException("Unable to convert to " + type);
+        }
+        try {
+            return ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), constructor, value);
+        } catch (Exception e) {
+            throw new Exception("Unable to convert ", getRealCause(e));
+        }
+    }
+    
+    private Object convertToCollection(Object obj, ReifiedType type) throws Exception {
+        ReifiedType valueType = type.getActualTypeArgument(0);
+        Collection newCol = (Collection) ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), 
+                                                                     CollectionRecipe.getCollection(toClass(type)));
+        if (obj.getClass().isArray()) {
+            for (int i = 0; i < Array.getLength(obj); i++) {
+                try {
+                    newCol.add(convert(Array.get(obj, i), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+                }
+            }
+        } else {
+            for (Object item : (Collection) obj) {
+                try {
+                    newCol.add(convert(item, valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting collection entry)", t);
+                }
+            }
+        }
+        return newCol;
+    }
+
+    private Object convertToDictionary(Object obj, ReifiedType type) throws Exception {
+        ReifiedType keyType = type.getActualTypeArgument(0);
+        ReifiedType valueType = type.getActualTypeArgument(1);
+        Dictionary newDic = new Hashtable();
+        if (obj instanceof Dictionary) {
+            Dictionary dic = (Dictionary) obj;
+            for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
+                Object key = keyEnum.nextElement();
+                try {
+                    newDic.put(convert(key, keyType), convert(dic.get(key), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        } else {
+            for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
+                try {
+                    newDic.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        }
+        return newDic;
+    }
+
+    private Object convertToMap(Object obj, ReifiedType type) throws Exception {
+        ReifiedType keyType = type.getActualTypeArgument(0);
+        ReifiedType valueType = type.getActualTypeArgument(1);
+        Map newMap = (Map) ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), 
+                                                       MapRecipe.getMap(toClass(type)));
+        if (obj instanceof Dictionary) {
+            Dictionary dic = (Dictionary) obj;
+            for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
+                Object key = keyEnum.nextElement();
+                try {
+                    newMap.put(convert(key, keyType), convert(dic.get(key), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        } else {
+            for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
+                try {
+                    newMap.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+                } catch (Exception t) {
+                    throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+                }
+            }
+        }
+        return newMap;
+    }
+
+    private Object convertToArray(Object obj, ReifiedType type) throws Exception {
+        if (obj instanceof Collection) {
+            obj = ((Collection) obj).toArray();
+        }
+        if (!obj.getClass().isArray()) {
+            throw new Exception("Unable to convert from " + obj + " to " + type);
+        }
+        ReifiedType componentType;
+        if (type.size() > 0) {
+            componentType = type.getActualTypeArgument(0);
+        } else {
+            componentType = new GenericType(type.getRawClass().getComponentType());
+        }
+        Object array = Array.newInstance(toClass(componentType), Array.getLength(obj));
+        for (int i = 0; i < Array.getLength(obj); i++) {
+            try {
+                Array.set(array, i, convert(Array.get(obj, i), componentType));
+            } catch (Exception t) {
+                throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+            }
+        }
+        return array;
+    }
+
+    public static boolean isAssignable(Object source, ReifiedType target) {
+        return source == null
+                || (target.size() == 0
+                    && unwrap(target.getRawClass()).isAssignableFrom(unwrap(source.getClass())));
+    }
+
+    private static Class unwrap(Class c) {
+        Class u = primitives.get(c);
+        return u != null ? u : c;
+    }
+    
+    private static final Map<Class, Class> primitives;
+    static {
+        primitives = new HashMap<Class, Class>();
+        primitives.put(byte.class, Byte.class);
+        primitives.put(short.class, Short.class);
+        primitives.put(char.class, Character.class);
+        primitives.put(int.class, Integer.class);
+        primitives.put(long.class, Long.class);
+        primitives.put(float.class, Float.class);
+        primitives.put(double.class, Double.class);
+        primitives.put(boolean.class, Boolean.class);
+    }
+
+    public Object convert(Object source, Type target) throws Exception {
+        return convert( source, new GenericType(target));
+    }
+
+    private Class toClass(ReifiedType type) {
+        return type.getRawClass();
+    }
+    
+}
\ No newline at end of file

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,920 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.container;
+
+import static org.apache.aries.blueprint.utils.ReflectionUtils.getRealCause;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.aries.blueprint.BeanProcessor;
+import org.apache.aries.blueprint.ComponentDefinitionRegistry;
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.Interceptor;
+import org.apache.aries.blueprint.di.AbstractRecipe;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.proxy.Collaborator;
+import org.apache.aries.blueprint.proxy.ProxyUtils;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.apache.aries.blueprint.utils.ReflectionUtils.PropertyDescriptor;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.reflect.BeanMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A <code>Recipe</code> to create POJOs.
+ *
+ * @version $Rev: 1055827 $, $Date: 2011-01-06 11:03:36 +0000 (Thu, 06 Jan 2011) $
+ */
+public class BeanRecipe extends AbstractRecipe {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BeanRecipe.class);
+
+    private final ExtendedBlueprintContainer blueprintContainer;
+    private final LinkedHashMap<String,Object> properties = new LinkedHashMap<String,Object>();
+    private final Object type;
+
+    private String initMethod;
+    private String destroyMethod;
+    private List<Recipe> explicitDependencies;
+    
+    private Recipe factory;
+    private String factoryMethod;
+    private List<Object> arguments;
+    private List<String> argTypes;
+    private boolean reorderArguments;
+    private final boolean allowsFieldInjection;
+    private BeanMetadata interceptorLookupKey;
+    
+
+    public BeanRecipe(String name, ExtendedBlueprintContainer blueprintContainer, Object type, boolean allowsFieldInjection) {
+        super(name);
+        this.blueprintContainer = blueprintContainer;
+        this.type = type;
+        this.allowsFieldInjection = allowsFieldInjection;
+    }
+
+    public Object getProperty(String name) {
+        return properties.get(name);
+    }
+
+    public Map<String, Object> getProperties() {
+        return new LinkedHashMap<String, Object>(properties);
+    }
+
+    public void setProperty(String name, Object value) {
+        properties.put(name, value);
+    }
+
+    public void setFactoryMethod(String method) {
+        this.factoryMethod = method;
+    }
+    
+    public void setFactoryComponent(Recipe factory) {
+        this.factory = factory;
+    }
+    
+    public void setArgTypes(List<String> argTypes) {
+        this.argTypes = argTypes;
+    }
+    
+    public void setArguments(List<Object> arguments) {
+        this.arguments = arguments;
+    }
+    
+    public void setReorderArguments(boolean reorder) {
+        this.reorderArguments = reorder;
+    }
+    
+    public void setInitMethod(String initMethod) {
+        this.initMethod = initMethod;
+    }
+    
+    public String getInitMethod() {
+        return initMethod;
+    }
+    
+    public void setDestroyMethod(String destroyMethod) {
+        this.destroyMethod = destroyMethod;
+    }
+    
+    public String getDestroyMethod() {
+        return destroyMethod;
+    }
+
+    public List<Recipe> getExplicitDependencies() {
+        return explicitDependencies;
+    }
+
+    public void setExplicitDependencies(List<Recipe> explicitDependencies) {
+        this.explicitDependencies = explicitDependencies;
+    }
+
+    public void setInterceptorLookupKey(BeanMetadata metadata) {
+    	interceptorLookupKey = metadata;
+    }
+    
+    @Override
+    public List<Recipe> getConstructorDependencies() {
+        List<Recipe> recipes = new ArrayList<Recipe>();
+        if (explicitDependencies != null) {
+            recipes.addAll(explicitDependencies);
+        }
+        if (arguments != null) {
+            for (Object argument : arguments) {
+                if (argument instanceof Recipe) {
+                    recipes.add((Recipe)argument);
+                }
+            }
+        }
+        return recipes;
+    }
+    
+    public List<Recipe> getDependencies() {
+        List<Recipe> recipes = new ArrayList<Recipe>();
+        for (Object o : properties.values()) {
+            if (o instanceof Recipe) {
+                Recipe recipe = (Recipe) o;
+                recipes.add(recipe);
+            }
+        }
+        recipes.addAll(getConstructorDependencies());
+        return recipes; 
+    }
+
+    private void instantiateExplicitDependencies() {
+        if (explicitDependencies != null) {
+            for (Recipe recipe : explicitDependencies) {
+                recipe.create();
+            }
+        }
+    }
+
+    @Override
+    protected Class loadClass(String className) {
+        ClassLoader loader = type instanceof Class ? ((Class) type).getClassLoader() : null;
+        ReifiedType t = loadType(className, loader);
+        return t != null ? t.getRawClass() : null;
+    }
+
+    @Override
+    protected ReifiedType loadType(String className) {
+        return loadType(className, type instanceof Class ? ((Class) type).getClassLoader() : null);
+    }
+
+    private Object getInstance() throws ComponentDefinitionException {
+        Object instance;
+        
+        // Instanciate arguments
+        List<Object> args = new ArrayList<Object>();
+        List<ReifiedType> argTypes = new ArrayList<ReifiedType>();
+        if (arguments != null) {
+            for (int i = 0; i < arguments.size(); i++) {
+                Object arg = arguments.get(i);
+                if (arg instanceof Recipe) {
+                    args.add(((Recipe) arg).create());
+                } else {
+                    args.add(arg);
+                }
+                if (this.argTypes != null) {
+                    argTypes.add(this.argTypes.get(i) != null ? loadType(this.argTypes.get(i)) : null);
+                }
+            }
+        }
+
+        if (factory != null) {
+            // look for instance method on factory object
+            Object factoryObj = factory.create();
+            
+            // If the factory is a service reference, we need to get hold of the actual proxy for the service
+            if (factoryObj instanceof ReferenceRecipe.ServiceProxyWrapper) {
+                try {
+                    factoryObj = ((ReferenceRecipe.ServiceProxyWrapper) factoryObj).convert(new ReifiedType(Object.class));
+                } catch (Exception e) {
+                    throw new ComponentDefinitionException("Error when instantiating bean " + getName() + " of class " + getType(), getRealCause(e));
+                }
+            }
+            
+            // Map of matching methods
+            Map<Method, List<Object>> matches = findMatchingMethods(factoryObj.getClass(), factoryMethod, true, args, argTypes);
+            if (matches.size() == 1) {
+                try {
+                    Map.Entry<Method, List<Object>> match = matches.entrySet().iterator().next();
+                    instance = invoke(match.getKey(), factoryObj, match.getValue().toArray());
+                } catch (Throwable e) {
+                    throw new ComponentDefinitionException("Error when instantiating bean " + getName() + " of class " + getType(), getRealCause(e));
+                }
+            } else if (matches.size() == 0) {
+                throw new ComponentDefinitionException("Unable to find a matching factory method " + factoryMethod + " on class " + factoryObj.getClass().getName() + " for arguments " + args + " when instanciating bean " + getName());
+            } else {
+                throw new ComponentDefinitionException("Multiple matching factory methods " + factoryMethod + " found on class " + factoryObj.getClass().getName() + " for arguments " + args + " when instanciating bean " + getName() + ": " + matches.keySet());
+            }
+        } else if (factoryMethod != null) {
+            // Map of matching methods
+            Map<Method, List<Object>> matches = findMatchingMethods(getType(), factoryMethod, false, args, argTypes);
+            if (matches.size() == 1) {
+                try {
+                    Map.Entry<Method, List<Object>> match = matches.entrySet().iterator().next();
+                    instance = invoke(match.getKey(), null, match.getValue().toArray());
+                } catch (Throwable e) {
+                    throw new ComponentDefinitionException("Error when instanciating bean " + getName() + " of class " + getType(), getRealCause(e));
+                }
+            } else if (matches.size() == 0) {
+                throw new ComponentDefinitionException("Unable to find a matching factory method " + factoryMethod + " on class " + getType().getName() + " for arguments " + args + " when instanciating bean " + getName());
+            } else {
+                throw new ComponentDefinitionException("Multiple matching factory methods " + factoryMethod + " found on class " + getType().getName() + " for arguments " + args + " when instanciating bean " + getName() + ": " + matches.keySet());
+            }
+        } else {
+            if (getType() == null) {
+                throw new ComponentDefinitionException("No factoryMethod nor class is defined for this bean");
+            }
+            // Map of matching constructors
+            Map<Constructor, List<Object>> matches = findMatchingConstructors(getType(), args, argTypes);
+            if (matches.size() == 1) {
+                try {
+                    Map.Entry<Constructor, List<Object>> match = matches.entrySet().iterator().next();
+                    instance = newInstance(match.getKey(), match.getValue().toArray());
+                } catch (Throwable e) {
+                    throw new ComponentDefinitionException("Error when instanciating bean " + getName() + " of class " + getType(), getRealCause(e));
+                }
+            } else if (matches.size() == 0) {
+                throw new ComponentDefinitionException("Unable to find a matching constructor on class " + getType().getName() + " for arguments " + args + " when instanciating bean " + getName());
+            } else {
+                throw new ComponentDefinitionException("Multiple matching constructors found on class " + getType().getName() + " for arguments " + args + " when instanciating bean " + getName() + ": " + matches.keySet());
+            }
+        }
+        
+        return instance;
+    }
+
+    private Map<Method, List<Object>> findMatchingMethods(Class type, String name, boolean instance, List<Object> args, List<ReifiedType> types) {
+        Map<Method, List<Object>> matches = new HashMap<Method, List<Object>>();
+        // Get constructors
+        List<Method> methods = new ArrayList<Method>(Arrays.asList(type.getMethods()));
+        // Discard any signature with wrong cardinality
+        for (Iterator<Method> it = methods.iterator(); it.hasNext();) {
+            Method mth = it.next();
+            if (!mth.getName().equals(name)) {
+                it.remove();
+            } else if (mth.getParameterTypes().length != args.size()) {
+                it.remove();
+            } else if (instance ^ !Modifier.isStatic(mth.getModifiers())) {
+                it.remove();
+            } else if (mth.isBridge()) {
+                it.remove();
+            }
+        }
+        
+        // on some JVMs (J9) hidden static methods are returned by Class.getMethods so we need to weed them out
+        // to reduce ambiguity
+        if (!instance) {
+        	methods = applyStaticHidingRules(methods);
+        }
+        
+        // Find a direct match with assignment
+        if (matches.size() != 1) {
+            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
+            for (Method mth : methods) {
+                boolean found = true;
+                List<Object> match = new ArrayList<Object>();
+                for (int i = 0; i < args.size(); i++) {
+                    ReifiedType argType = new GenericType(mth.getGenericParameterTypes()[i]);
+                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
+                        found = false;
+                        break;
+                    }
+                    if (!AggregateConverter.isAssignable(args.get(i), argType)) {
+                        found = false;
+                        break;
+                    }
+                    try {
+                        match.add(convert(args.get(i), mth.getGenericParameterTypes()[i]));
+                    } catch (Throwable t) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found) {
+                    nmatches.put(mth, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        // Find a direct match with conversion
+        if (matches.size() != 1) {
+            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
+            for (Method mth : methods) {
+                boolean found = true;
+                List<Object> match = new ArrayList<Object>();
+                for (int i = 0; i < args.size(); i++) {
+                    ReifiedType argType = new GenericType(mth.getGenericParameterTypes()[i]);
+                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
+                        found = false;
+                        break;
+                    }
+                    try {
+                        Object val = convert(args.get(i), argType);
+                        match.add(val);
+                    } catch (Throwable t) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found) {
+                    nmatches.put(mth, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        // Start reordering with assignment
+        if (matches.size() != 1 && reorderArguments && args.size() > 1) {
+            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
+            for (Method mth : methods) {
+                ArgumentMatcher matcher = new ArgumentMatcher(mth.getGenericParameterTypes(), false);
+                List<Object> match = matcher.match(args, types);
+                if (match != null) {
+                    nmatches.put(mth, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        // Start reordering with conversion
+        if (matches.size() != 1 && reorderArguments && args.size() > 1) {
+            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
+            for (Method mth : methods) {
+                ArgumentMatcher matcher = new ArgumentMatcher(mth.getGenericParameterTypes(), true);
+                List<Object> match = matcher.match(args, types);
+                if (match != null) {
+                    nmatches.put(mth, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        
+        return matches;
+    }
+    
+    private static List<Method> applyStaticHidingRules(Collection<Method> methods) {
+    	List<Method> result = new ArrayList<Method>(methods.size());
+    	for (Method m : methods) {
+    		boolean toBeAdded = true;
+
+    		Iterator<Method> it = result.iterator();
+    		inner: while (it.hasNext()) {
+    			Method other = it.next();
+    			if (hasIdenticalParameters(m, other)) {
+    				Class<?> mClass = m.getDeclaringClass();
+    				Class<?> otherClass = other.getDeclaringClass();
+    				
+    				if (mClass.isAssignableFrom(otherClass)) {
+    					toBeAdded = false;
+    					break inner;
+    				} else if (otherClass.isAssignableFrom(mClass)) {
+    					it.remove();
+    				}
+    			}
+    		}
+    		
+    		if (toBeAdded) result.add(m);
+    	}
+    	
+    	return result;
+    }
+    
+    private static boolean hasIdenticalParameters(Method one, Method two) {
+		Class<?>[] oneTypes = one.getParameterTypes();
+		Class<?>[] twoTypes = two.getParameterTypes();
+    	
+		if (oneTypes.length != twoTypes.length) return false;
+		
+		for (int i=0; i<oneTypes.length; i++) {
+			if (!oneTypes[i].equals(twoTypes[i])) return false;
+		}
+		
+		return true;
+    }
+
+    private Map<Constructor, List<Object>> findMatchingConstructors(Class type, List<Object> args, List<ReifiedType> types) {
+        Map<Constructor, List<Object>> matches = new HashMap<Constructor, List<Object>>();
+        // Get constructors
+        List<Constructor> constructors = new ArrayList<Constructor>(Arrays.asList(type.getConstructors()));
+        // Discard any signature with wrong cardinality
+        for (Iterator<Constructor> it = constructors.iterator(); it.hasNext();) {
+            if (it.next().getParameterTypes().length != args.size()) {
+                it.remove();
+            }
+        }
+        // Find a direct match with assignment
+        if (matches.size() != 1) {
+            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
+            for (Constructor cns : constructors) {
+                boolean found = true;
+                List<Object> match = new ArrayList<Object>();
+                for (int i = 0; i < args.size(); i++) {
+                    ReifiedType argType = new GenericType(cns.getGenericParameterTypes()[i]);
+                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
+                        found = false;
+                        break;
+                    }
+                    if (!AggregateConverter.isAssignable(args.get(i), argType)) {
+                        found = false;
+                        break;
+                    }
+                    try {
+                        match.add(convert(args.get(i), cns.getGenericParameterTypes()[i]));
+                    } catch (Throwable t) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found) {
+                    nmatches.put(cns, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        // Find a direct match with conversion
+        if (matches.size() != 1) {
+            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
+            for (Constructor cns : constructors) {
+                boolean found = true;
+                List<Object> match = new ArrayList<Object>();
+                for (int i = 0; i < args.size(); i++) {
+                    ReifiedType argType = new GenericType(cns.getGenericParameterTypes()[i]);
+                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
+                        found = false;
+                        break;
+                    }
+                    try {
+                        Object val = convert(args.get(i), argType);
+                        match.add(val);
+                    } catch (Throwable t) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found) {
+                    nmatches.put(cns, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        // Start reordering with assignment
+        if (matches.size() != 1 && reorderArguments && arguments.size() > 1) {
+            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
+            for (Constructor cns : constructors) {
+                ArgumentMatcher matcher = new ArgumentMatcher(cns.getGenericParameterTypes(), false);
+                List<Object> match = matcher.match(args, types);
+                if (match != null) {
+                    nmatches.put(cns, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        // Start reordering with conversion
+        if (matches.size() != 1 && reorderArguments && arguments.size() > 1) {
+            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
+            for (Constructor cns : constructors) {
+                ArgumentMatcher matcher = new ArgumentMatcher(cns.getGenericParameterTypes(), true);
+                List<Object> match = matcher.match(args, types);
+                if (match != null) {
+                    nmatches.put(cns, match);
+                }
+            }
+            if (nmatches.size() > 0) {
+                matches = nmatches;
+            }
+        }
+        return matches;
+    }
+
+    /**
+     * Returns init method (if any). Throws exception if the init-method was set explicitly on the bean
+     * and the method is not found on the instance.
+     */
+    protected Method getInitMethod(Object instance) throws ComponentDefinitionException {
+        Method method = null;        
+        if (initMethod != null && initMethod.length() > 0) {
+            method = ReflectionUtils.getLifecycleMethod(instance.getClass(), initMethod);
+            if (method == null) {
+                throw new ComponentDefinitionException("Component '" + getName() + "' does not have init-method: " + initMethod);
+            }
+        }
+        return method;
+    }
+
+    /**
+     * Returns destroy method (if any). Throws exception if the destroy-method was set explicitly on the bean
+     * and the method is not found on the instance.
+     */
+    public Method getDestroyMethod(Object instance) throws ComponentDefinitionException {
+        Method method = null;        
+        if (destroyMethod != null && destroyMethod.length() > 0) {
+            method = ReflectionUtils.getLifecycleMethod(instance.getClass(), destroyMethod);
+            if (method == null) {
+                throw new ComponentDefinitionException("Component '" + getName() + "' does not have destroy-method: " + destroyMethod);
+            }
+        }
+        return method;
+    }
+    
+    /**
+     * Small helper class, to construct a chain of BeanCreators.
+     * <br> 
+     * Each bean creator in the chain will return a bean that has been 
+     * processed by every BeanProcessor in the chain before it.
+     */
+    private static class BeanCreatorChain implements BeanProcessor.BeanCreator {
+        public enum ChainType{Before,After};
+        private final BeanProcessor.BeanCreator parentBeanCreator;
+        private final BeanProcessor parentBeanProcessor;
+        private final BeanMetadata beanData;
+        private final String beanName;        
+        private final ChainType when;
+        public BeanCreatorChain(BeanProcessor.BeanCreator parentBeanCreator, 
+                                BeanProcessor parentBeanProcessor,
+                                BeanMetadata beanData,
+                                String beanName,
+                                ChainType when){
+            this.parentBeanCreator = parentBeanCreator;
+            this.parentBeanProcessor = parentBeanProcessor;
+            this.beanData = beanData;
+            this.beanName = beanName;
+            this.when = when;
+        }
+
+        public Object getBean() {
+            Object previousBean = parentBeanCreator.getBean();
+            Object processed = null;
+            switch(when){
+                case Before :
+                  processed = parentBeanProcessor.beforeInit(previousBean, beanName, parentBeanCreator, beanData);
+                  break;
+                case After:
+                  processed = parentBeanProcessor.afterInit(previousBean, beanName, parentBeanCreator, beanData);
+                  break;
+            }
+            return processed;
+        }   
+    }
+    
+    private Object runBeanProcPreInit(Object obj){
+        String beanName = getName();
+        BeanMetadata beanData = (BeanMetadata) blueprintContainer
+          .getComponentDefinitionRegistry().getComponentDefinition(beanName);        
+        List<BeanProcessor> processors = blueprintContainer.getProcessors(BeanProcessor.class);
+        
+        //The start link of the chain, that provides the 
+        //original, unprocessed bean to the head of the chain.
+        BeanProcessor.BeanCreator initialBeanCreator = new BeanProcessor.BeanCreator() {            
+            public Object getBean() {
+                Object obj = getInstance();
+                //getinit, getdestroy, addpartial object don't need calling again.
+                //however, property injection does.
+                setProperties(obj);
+                return obj;
+            }
+        };
+
+        BeanProcessor.BeanCreator currentCreator = initialBeanCreator;
+        for(BeanProcessor processor : processors){
+            obj = processor.beforeInit(obj, getName(), currentCreator, beanData);
+            currentCreator = new BeanCreatorChain(currentCreator, processor, beanData, beanName, BeanCreatorChain.ChainType.Before);
+        }
+        return obj;
+    }
+    
+    private void runBeanProcInit(Method initMethod, Object obj){
+        // call init method
+        if (initMethod != null) {
+            try {
+                invoke(initMethod, obj, (Object[]) null);
+            } catch (Throwable t) {
+                throw new ComponentDefinitionException("Unable to intialize bean " + getName(), getRealCause(t));
+            }
+        }   
+    }
+    
+    private Object runBeanProcPostInit(Object obj){
+        String beanName = getName();
+        BeanMetadata beanData = (BeanMetadata) blueprintContainer
+          .getComponentDefinitionRegistry().getComponentDefinition(beanName);        
+        List<BeanProcessor> processors = blueprintContainer.getProcessors(BeanProcessor.class);
+        
+        //The start link of the chain, that provides the 
+        //original, unprocessed bean to the head of the chain.
+        BeanProcessor.BeanCreator initialBeanCreator = new BeanProcessor.BeanCreator() {            
+            public Object getBean() {                                
+                Object obj = getInstance();
+                //getinit, getdestroy, addpartial object don't need calling again.
+                //however, property injection does.
+                setProperties(obj);
+                //as this is the post init chain, new beans need to go thru 
+                //the pre-init chain, and then have init called, before 
+                //being passed along the post-init chain.
+                obj = runBeanProcPreInit(obj);
+                runBeanProcInit(getInitMethod(obj), obj);
+                return obj;
+            }
+        };
+
+        BeanProcessor.BeanCreator currentCreator = initialBeanCreator;
+        for(BeanProcessor processor : processors){
+            obj = processor.afterInit(obj, getName(), currentCreator, beanData);
+            currentCreator = new BeanCreatorChain(currentCreator, processor, beanData, beanName, BeanCreatorChain.ChainType.After);
+        }
+        return obj;
+    }    
+    
+    private Object addInterceptors(final Object original)
+            throws ComponentDefinitionException {
+
+        Object intercepted = null;
+        ComponentDefinitionRegistry reg = blueprintContainer
+                .getComponentDefinitionRegistry();
+        List<Interceptor> interceptors = reg.getInterceptors(interceptorLookupKey);
+        if (interceptors != null && interceptors.size() > 0) {
+            try {
+              Bundle b = FrameworkUtil.getBundle(original.getClass());
+              if (b == null) {
+                // we have a class from the framework parent, so use our bundle for proxying.
+                b = blueprintContainer.getBundleContext().getBundle();
+              }
+              intercepted = BlueprintExtender.getProxyManager().createProxy(b, 
+                  ProxyUtils.asList(original.getClass()), ProxyUtils.passThrough(original), 
+                  new Collaborator(interceptorLookupKey, interceptors));
+            } catch (org.apache.aries.proxy.UnableToProxyException e) {
+                  Bundle b = blueprintContainer.getBundleContext().getBundle();
+                  throw new ComponentDefinitionException("Unable to create proxy for bean " + name + " in bundle " + b.getSymbolicName() + " version " + b.getVersion(), e);
+            }
+        } else {
+            intercepted = original;
+        }
+        return intercepted;
+    }
+        
+    @Override
+    protected Object internalCreate() throws ComponentDefinitionException {
+        
+        instantiateExplicitDependencies();
+
+        Object obj = getInstance();
+                
+        // check for init lifecycle method (if any)
+        Method initMethod = getInitMethod(obj);
+        
+        // check for destroy lifecycle method (if any)
+        getDestroyMethod(obj);
+        
+        // Add partially created object to the container
+//        if (initMethod == null) {
+            addPartialObject(obj);
+//        }
+
+        // inject properties
+        setProperties(obj);
+        
+        obj = runBeanProcPreInit(obj);
+        
+        runBeanProcInit(initMethod, obj);
+        
+        obj = runBeanProcPostInit(obj);
+        
+        obj = addInterceptors(obj);
+        
+        return obj;
+    }
+    
+    @Override
+    public void destroy(Object obj) {
+        for (BeanProcessor processor : blueprintContainer.getProcessors(BeanProcessor.class)) {
+            processor.beforeDestroy(obj, getName());
+        }
+        try {
+            Method method = getDestroyMethod(obj);
+            if (method != null) {
+                invoke(method, obj, (Object[]) null);
+            }
+        } catch (Exception e) {
+            LOGGER.info("Error invoking destroy method", getRealCause(e));
+        }
+        for (BeanProcessor processor : blueprintContainer.getProcessors(BeanProcessor.class)) {
+            processor.afterDestroy(obj, getName());
+        }
+    }
+
+    public void setProperties(Object instance) throws ComponentDefinitionException {
+        // clone the properties so they can be used again
+        Map<String,Object> propertyValues = new LinkedHashMap<String,Object>(properties);
+        setProperties(propertyValues, instance, instance.getClass());
+    }
+
+    public Class getType() {
+        if (type instanceof Class) {
+            return (Class) type;
+        } else if (type instanceof String) {
+            return loadClass((String) type);
+        } else {
+            return null;
+        }
+    }
+
+    private void setProperties(Map<String, Object> propertyValues, Object instance, Class clazz) {
+        // set remaining properties
+        for (Map.Entry<String, Object> entry : propertyValues.entrySet()) {
+            String propertyName = entry.getKey();
+            Object propertyValue = entry.getValue();
+
+            setProperty(instance, clazz, propertyName, propertyValue);
+        }
+
+    }
+
+    private void setProperty(Object instance, Class clazz, String propertyName, Object propertyValue) {
+        String[] names = propertyName.split("\\.");
+        for (int i = 0; i < names.length - 1; i++) {
+            PropertyDescriptor pd = getPropertyDescriptor(clazz, names[i]);
+            if (pd.allowsGet()) {
+                try {
+                    instance = pd.get(instance, blueprintContainer);
+                } catch (Exception e) {
+                    throw new ComponentDefinitionException("Error getting property: " + names[i] + " on bean " + getName() + " when setting property " + propertyName + " on class " + clazz.getName(), getRealCause(e));
+                }
+                if (instance == null) {
+                    throw new ComponentDefinitionException("Error setting compound property " + propertyName + " on bean " + getName() + ". Property " + names[i] + " is null");
+                }
+                clazz = instance.getClass();
+            } else {
+                throw new ComponentDefinitionException("No getter for " + names[i] + " property on bean " + getName() + " when setting property " + propertyName + " on class " + clazz.getName());
+            }
+        }
+        
+        // Instantiate value
+        if (propertyValue instanceof Recipe) {
+            propertyValue = ((Recipe) propertyValue).create();
+        }
+
+        final PropertyDescriptor pd = getPropertyDescriptor(clazz, names[names.length - 1]);
+        if (pd.allowsSet()) {
+            try {
+                pd.set(instance, propertyValue, blueprintContainer);
+            } catch (Exception e) {
+                throw new ComponentDefinitionException("Error setting property: " + pd, getRealCause(e));
+            }
+        } else {
+            throw new ComponentDefinitionException("No setter for " + names[names.length - 1] + " property");
+        }
+    }
+
+    private ReflectionUtils.PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String name) {
+        for (ReflectionUtils.PropertyDescriptor pd : ReflectionUtils.getPropertyDescriptors(clazz, allowsFieldInjection)) {
+            if (pd.getName().equals(name)) {
+                return pd;
+            }
+        }
+        throw new ComponentDefinitionException("Unable to find property descriptor " + name + " on class " + clazz.getName());
+    }
+        
+    private Object invoke(Method method, Object instance, Object... args) throws Exception {
+        return ReflectionUtils.invoke(blueprintContainer.getAccessControlContext(), method, instance, args);        
+    }
+    
+    private Object newInstance(Constructor constructor, Object... args) throws Exception {
+        return ReflectionUtils.newInstance(blueprintContainer.getAccessControlContext(), constructor, args);         
+    }
+    
+    private static Object UNMATCHED = new Object();
+
+    private class ArgumentMatcher {
+
+        private final List<TypeEntry> entries;
+        private final boolean convert;
+
+        public ArgumentMatcher(Type[] types, boolean convert) {
+            entries = new ArrayList<TypeEntry>();
+            for (Type type : types) {
+                entries.add(new TypeEntry(new GenericType(type)));
+            }
+            this.convert = convert;
+        }
+
+        public List<Object> match(List<Object> arguments, List<ReifiedType> forcedTypes) {
+            if (find(arguments, forcedTypes)) {
+                return getArguments();
+            }
+            return null;
+        }
+
+        private List<Object> getArguments() {
+            List<Object> list = new ArrayList<Object>();
+            for (TypeEntry entry : entries) {
+                if (entry.argument == UNMATCHED) {
+                    throw new RuntimeException("There are unmatched types");
+                } else {
+                    list.add(entry.argument);
+                }
+            }
+            return list;
+        }
+
+        private boolean find(List<Object> arguments, List<ReifiedType> forcedTypes) {
+            if (entries.size() == arguments.size()) {
+                boolean matched = true;
+                for (int i = 0; i < arguments.size() && matched; i++) {
+                    matched = find(arguments.get(i), forcedTypes.get(i));
+                }
+                return matched;
+            }
+            return false;
+        }
+
+        private boolean find(Object arg, ReifiedType forcedType) {
+            for (TypeEntry entry : entries) {
+                Object val = arg;
+                if (entry.argument != UNMATCHED) {
+                    continue;
+                }
+                if (forcedType != null) {
+                    if (!forcedType.equals(entry.type)) {
+                        continue;
+                    }
+                } else if (arg != null) {
+                    if (convert) {
+                        try {
+                            // TODO: call canConvert instead of convert()
+                            val = convert(arg, entry.type);
+                        } catch (Throwable t) {
+                            continue;
+                        }
+                    } else {
+                        if (!AggregateConverter.isAssignable(arg, entry.type)) {
+                            continue;
+                        }
+                    }
+                }
+                entry.argument = val;
+                return true;
+            }
+            return false;
+        }
+
+    }
+
+    private static class TypeEntry {
+
+        private final ReifiedType type;
+        private Object argument;
+
+        public TypeEntry(ReifiedType type) {
+            this.type = type;
+            this.argument = UNMATCHED;
+        }
+
+    }
+
+}