aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From z..@apache.org
Subject svn commit: r1075143 [10/23] - in /aries/tags/blueprint-0.2.1: ./ 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-a...
Date Sun, 27 Feb 2011 20:50:51 GMT
Added: aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=1075143&view=auto
==============================================================================
--- aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java (added)
+++ aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java Sun Feb 27 20:50:38 2011
@@ -0,0 +1,940 @@
+/*
+ * 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 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.AsmInterceptorWrapper;
+import org.apache.aries.blueprint.proxy.CgLibInterceptorWrapper;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.apache.aries.blueprint.utils.ReflectionUtils.PropertyDescriptor;
+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: 978875 $, $Date: 2010-07-24 14:45:05 +0100 (Sat, 24 Jul 2010) $
+ */
+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 BeanProcessor.BeanCreator parentBeanCreator;
+        private BeanProcessor parentBeanProcessor;
+        private BeanMetadata beanData;
+        private String beanName;        
+        private 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(Object original)
+            throws ComponentDefinitionException {
+
+        Object intercepted = null;
+        ComponentDefinitionRegistry reg = blueprintContainer
+                .getComponentDefinitionRegistry();
+        List<Interceptor> interceptors = reg.getInterceptors(interceptorLookupKey);
+        if (interceptors != null && interceptors.size() > 0) {
+            boolean asmAvailable = false;
+            try {
+                // Try load load an asm class (to make sure it's actually
+                // available)
+                getClass().getClassLoader().loadClass(
+                        "org.objectweb.asm.ClassVisitor");
+                LOGGER.debug("asm available for interceptors");
+                asmAvailable = true;
+            } catch (Throwable t) {
+                try {
+                    // Try load load a cglib class (to make sure it's actually
+                    // available)
+                    getClass().getClassLoader().loadClass(
+                            "net.sf.cglib.proxy.Enhancer");
+                } catch (Throwable u) {
+                    throw new ComponentDefinitionException(
+                            "Interceptors have been configured but neither asm nor cglib are available",
+                            u);
+                }
+            }
+            if (asmAvailable) {
+                // if asm is available we can proxy the original object with the
+                // AsmInterceptorWrapper
+                intercepted = AsmInterceptorWrapper.createProxyObject(original
+                        .getClass().getClassLoader(), interceptorLookupKey, interceptors,
+                        original, original.getClass());
+            } else {
+                LOGGER.debug("cglib available for interceptors");
+                // otherwise we're using cglib and need to use the interfaces
+                // with the CgLibInterceptorWrapper
+                intercepted = CgLibInterceptorWrapper.createProxyObject(
+                        original.getClass().getClassLoader(), interceptorLookupKey,
+                        interceptors, original, original.getClass()
+                                .getInterfaces());
+            }
+
+        } 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.getAccessControlContext());
+                } 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.getAccessControlContext());
+            } 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 List<TypeEntry> entries;
+        private 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;
+        }
+
+    }
+
+}

Added: aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java?rev=1075143&view=auto
==============================================================================
--- aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java (added)
+++ aries/tags/blueprint-0.2.1/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java Sun Feb 27 20:50:38 2011
@@ -0,0 +1,843 @@
+/*
+ * 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.FileNotFoundException;
+import java.net.URI;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.DomainCombiner;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.aries.blueprint.BlueprintConstants;
+import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
+import org.apache.aries.blueprint.ExtendedBeanMetadata;
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.NamespaceHandler;
+import org.apache.aries.blueprint.Processor;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.Repository;
+import org.apache.aries.blueprint.namespace.ComponentDefinitionRegistryImpl;
+import org.apache.aries.blueprint.namespace.NamespaceHandlerRegistryImpl;
+import org.apache.aries.blueprint.reflect.MetadataUtil;
+import org.apache.aries.blueprint.reflect.PassThroughMetadataImpl;
+import org.apache.aries.blueprint.utils.HeaderParser;
+import org.apache.aries.blueprint.utils.JavaUtils;
+import org.apache.aries.blueprint.utils.HeaderParser.PathElement;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.osgi.service.blueprint.container.BlueprintListener;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.Converter;
+import org.osgi.service.blueprint.container.NoSuchComponentException;
+import org.osgi.service.blueprint.reflect.BeanArgument;
+import org.osgi.service.blueprint.reflect.BeanMetadata;
+import org.osgi.service.blueprint.reflect.BeanProperty;
+import org.osgi.service.blueprint.reflect.CollectionMetadata;
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.osgi.service.blueprint.reflect.MapEntry;
+import org.osgi.service.blueprint.reflect.MapMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
+import org.osgi.service.blueprint.reflect.PropsMetadata;
+import org.osgi.service.blueprint.reflect.RefMetadata;
+import org.osgi.service.blueprint.reflect.ReferenceListener;
+import org.osgi.service.blueprint.reflect.RegistrationListener;
+import org.osgi.service.blueprint.reflect.ServiceMetadata;
+import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
+import org.osgi.service.blueprint.reflect.Target;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO: javadoc
+ *
+ * @version $Rev: 1072950 $, $Date: 2011-02-21 12:40:13 +0000 (Mon, 21 Feb 2011) $
+ */
+public class BlueprintContainerImpl implements ExtendedBlueprintContainer, NamespaceHandlerRegistry.Listener, Runnable, SatisfiableRecipe.SatisfactionListener {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BlueprintContainerImpl.class);
+
+    private enum State {
+        Unknown,
+        WaitForNamespaceHandlers,
+        Populated,
+        WaitForInitialReferences,
+        InitialReferencesSatisfied,
+        WaitForInitialReferences2,
+        Create,
+        Created,
+        Failed,
+    }
+
+    private final BundleContext bundleContext;
+    private final Bundle extenderBundle;
+    private final BlueprintListener eventDispatcher;
+    private final NamespaceHandlerRegistry handlers;
+    private final List<Object> pathList;
+    private final ComponentDefinitionRegistryImpl componentDefinitionRegistry;
+    private final AggregateConverter converter;
+    private final ScheduledExecutorService executors;
+    private Set<URI> namespaces;
+    private State state = State.Unknown;
+    private NamespaceHandlerRegistry.NamespaceHandlerSet handlerSet;
+    private boolean destroyed;
+    private Parser parser;
+    private BlueprintRepository repository;
+    private ServiceRegistration registration;
+    private List<Processor> processors;
+    private final Object satisfiablesLock = new Object();
+    private Map<String, List<SatisfiableRecipe>> satisfiables;
+    private long timeout = 5 * 60 * 1000;
+    private boolean waitForDependencies = true;
+    private boolean xmlValidation = true;
+    private ScheduledFuture timeoutFuture;
+    private final AtomicBoolean scheduled = new AtomicBoolean();
+    private final AtomicBoolean running = new AtomicBoolean();
+    private List<ServiceRecipe> services;
+    private AccessControlContext accessControlContext;
+    private final IdSpace tempRecipeIdSpace = new IdSpace();
+    
+    public BlueprintContainerImpl(BundleContext bundleContext, Bundle extenderBundle, BlueprintListener eventDispatcher, NamespaceHandlerRegistry handlers, ScheduledExecutorService executors, List<Object> pathList) {
+        this.bundleContext = bundleContext;
+        this.extenderBundle = extenderBundle;
+        this.eventDispatcher = eventDispatcher;
+        this.handlers = handlers;
+        this.pathList = pathList;
+        this.converter = new AggregateConverter(this);
+        this.componentDefinitionRegistry = new ComponentDefinitionRegistryImpl();
+        this.executors = executors;
+        this.processors = new ArrayList<Processor>();
+        if (System.getSecurityManager() != null) {
+            this.accessControlContext = createAccessControlContext();
+        }
+    }
+
+    public Bundle getExtenderBundle() {
+        return extenderBundle;
+    }
+
+    public <T extends Processor> List<T> getProcessors(Class<T> clazz) {
+        List<T> p = new ArrayList<T>();
+        for (Processor processor : processors) {
+            if (clazz.isInstance(processor)) {
+                p.add(clazz.cast(processor));
+            }
+        }
+        return p;
+    }
+
+    public BlueprintListener getEventDispatcher() {
+        return eventDispatcher;
+    }
+
+    private void checkDirectives() {
+        Bundle bundle = bundleContext.getBundle();
+        Dictionary headers = bundle.getHeaders();
+        String symbolicName = (String)headers.get(Constants.BUNDLE_SYMBOLICNAME);
+        List<PathElement> paths = HeaderParser.parseHeader(symbolicName);
+
+        String timeoutDirective = paths.get(0).getDirective(BlueprintConstants.TIMEOUT_DIRECTIVE);
+        if (timeoutDirective != null) {
+            LOGGER.debug("Timeout directive: {}", timeoutDirective);
+            timeout = Integer.parseInt(timeoutDirective);
+        }
+
+        String graceperiod = paths.get(0).getDirective(BlueprintConstants.GRACE_PERIOD);
+        if (graceperiod != null) {
+            LOGGER.debug("Grace-period directive: {}", graceperiod);
+            waitForDependencies = Boolean.parseBoolean(graceperiod);
+        }
+
+        String xmlValidationDirective = paths.get(0).getDirective(BlueprintConstants.XML_VALIDATION);
+        if (xmlValidationDirective != null) {
+            LOGGER.debug("Xml-validation directive: {}", xmlValidationDirective);
+            xmlValidation = Boolean.parseBoolean(xmlValidationDirective);
+        }
+    }
+    
+    public void schedule() {
+        if (scheduled.compareAndSet(false, true)) {
+            executors.submit(this);
+        }
+    }
+    
+    public void run() {
+        scheduled.set(false);
+        synchronized (scheduled) {
+            synchronized (running) {
+                running.set(true);
+                try {
+                    doRun();
+                } finally {
+                    running.set(false);
+                    running.notifyAll();
+                }
+            }
+        }
+    }
+
+    /**
+     * This method must be called inside a synchronized block to ensure this method is not run concurrently
+     */
+    private void doRun() {
+        try {
+            for (;;) {
+                if (destroyed) {
+                    return;
+                }
+                LOGGER.debug("Running blueprint container for bundle {} in state {}", bundleContext.getBundle().getSymbolicName(), state);
+                switch (state) {
+                    case Unknown:
+                        checkDirectives();
+                        eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.CREATING, getBundleContext().getBundle(), getExtenderBundle()));
+                        parser = new Parser();
+                        parser.parse(getResources());
+                        namespaces = parser.getNamespaces();
+                        handlerSet = handlers.getNamespaceHandlers(namespaces, getBundleContext().getBundle());
+                        handlerSet.addListener(this);
+                        state = State.WaitForNamespaceHandlers;
+                        break;
+                    case WaitForNamespaceHandlers:
+                    {
+                        List<String> missing = new ArrayList<String>();
+                        for (URI ns : namespaces) {
+                            if (handlerSet.getNamespaceHandler(ns) == null) {
+                                missing.add("(&(" + Constants.OBJECTCLASS + "=" + NamespaceHandler.class.getName() + ")(" + NamespaceHandlerRegistryImpl.NAMESPACE + "=" + ns + "))");
+                            }
+                        }
+                        if (missing.size() > 0) {
+                            LOGGER.warn("Bundle " + bundleContext.getBundle().getSymbolicName() + " is waiting for namespace handlers " + missing);
+                            eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.GRACE_PERIOD, getBundleContext().getBundle(), getExtenderBundle(), missing.toArray(new String[missing.size()])));
+                            return;
+                        }
+                        componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintContainer", this));
+                        componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintBundle", bundleContext.getBundle()));
+                        componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintBundleContext", bundleContext));
+                        componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintConverter", converter));
+                        if (xmlValidation) {
+                            parser.validate(handlerSet.getSchema());
+                        }
+                        parser.populate(handlerSet, componentDefinitionRegistry);
+                        state = State.Populated;
+                        break;
+                    }
+                    case Populated:
+                        getRepository();
+                        trackServiceReferences();
+                        Runnable r = new Runnable() {
+                            public void run() {
+                                synchronized (scheduled) {
+                                    Throwable t = new TimeoutException();
+                                    state = State.Failed;
+                                    String[] missingDependecies = getMissingDependencies();
+                                    unregisterServices();
+                                    untrackServiceReferences();
+                                    destroyComponents();
+                                    LOGGER.error("Unable to start blueprint container for bundle " + bundleContext.getBundle().getSymbolicName() + " due to unresolved dependencies " + Arrays.asList(missingDependecies), t);
+                                    eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.FAILURE, getBundleContext().getBundle(), getExtenderBundle(), missingDependecies, t));
+                                }
+                            }
+                        };
+                        timeoutFuture = executors.schedule(r, timeout, TimeUnit.MILLISECONDS);
+                        state = State.WaitForInitialReferences;
+                        break;
+                    case WaitForInitialReferences:
+                        if (waitForDependencies) {
+                            String[] missingDependencies = getMissingDependencies();
+                            if (missingDependencies.length > 0) {
+                                eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.GRACE_PERIOD, getBundleContext().getBundle(), getExtenderBundle(), missingDependencies));
+                                return;
+                            }
+                        }
+                        state = State.InitialReferencesSatisfied;
+                        break;
+                    case InitialReferencesSatisfied:
+                        processTypeConverters();
+                        processProcessors();
+                        state = State.WaitForInitialReferences2;
+                        break;
+                    case WaitForInitialReferences2:
+                        if (waitForDependencies) {
+                            String[] missingDependencies = getMissingDependencies();
+                            if (missingDependencies.length > 0) {
+                                eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.GRACE_PERIOD, getBundleContext().getBundle(), getExtenderBundle(), missingDependencies));
+                                return;
+                            }
+                        }                       
+                        state = State.Create;
+                        break;
+                    case Create:
+                        timeoutFuture.cancel(false);
+                        registerServices();
+                        instantiateEagerComponents();
+
+                        // Register the BlueprintContainer in the OSGi registry
+                        int bs = bundleContext.getBundle().getState();
+                        if (registration == null && (bs == Bundle.ACTIVE || bs == Bundle.STARTING)) {
+                            Properties props = new Properties();
+                            props.put(BlueprintConstants.CONTAINER_SYMBOLIC_NAME_PROPERTY,
+                                      bundleContext.getBundle().getSymbolicName());
+                            props.put(BlueprintConstants.CONTAINER_VERSION_PROPERTY,
+                                      JavaUtils.getBundleVersion(bundleContext.getBundle()));
+                            registration = registerService(new String [] { BlueprintContainer.class.getName() }, this, props);
+                            eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.CREATED, getBundleContext().getBundle(), getExtenderBundle()));
+                            state = State.Created;
+                        }
+                        break;
+                    case Created:
+                    case Failed:
+                        return;
+                }
+            }
+        } catch (Throwable t) {
+            state = State.Failed;
+            if (timeoutFuture != null) {
+                timeoutFuture.cancel(false);
+            }
+            unregisterServices();
+            untrackServiceReferences();
+            destroyComponents();
+            LOGGER.error("Unable to start blueprint container for bundle " + bundleContext.getBundle().getSymbolicName(), t);
+            eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.FAILURE, getBundleContext().getBundle(), getExtenderBundle(), t));
+        }
+    }
+
+    private List<URL> getResources() throws FileNotFoundException {
+        List<URL> resources = new ArrayList<URL>();
+        for (Object path : pathList) {
+            if (path instanceof URL) {
+                resources.add((URL) path);                
+            } else if (path instanceof String) {
+                URL url = bundleContext.getBundle().getEntry((String) path);
+                if (url == null) {
+                    throw new FileNotFoundException("Unable to find configuration file for " + path);
+                } else {
+                    resources.add(url);
+                }
+            } else {
+                throw new IllegalArgumentException("Unexpected path type: " + path.getClass());
+            }
+        }
+        return resources;
+    }
+    
+    public Class loadClass(final String name) throws ClassNotFoundException {
+        if (accessControlContext == null) {
+            return bundleContext.getBundle().loadClass(name);
+        } else {
+            try {
+                return AccessController.doPrivileged(new PrivilegedExceptionAction<Class>() {
+                    public Class run() throws Exception {
+                        return bundleContext.getBundle().loadClass(name);
+                    }            
+                }, accessControlContext);
+            } catch (PrivilegedActionException e) {
+                Exception cause = e.getException();
+                if (cause instanceof ClassNotFoundException) {
+                    throw (ClassNotFoundException) cause;
+                }
+                throw new IllegalStateException("Unexpected checked exception", cause);
+            }
+        }
+    }
+    
+    public ServiceRegistration registerService(final String[] classes, final Object service, final Dictionary properties) {
+        if (accessControlContext == null) {
+            return bundleContext.registerService(classes, service, properties);
+        } else {
+            return AccessController.doPrivileged(new PrivilegedAction<ServiceRegistration>() {
+                public ServiceRegistration run() {
+                    return bundleContext.registerService(classes, service, properties);
+                }            
+            }, accessControlContext);
+        }
+    }
+    
+    public Object getService(final ServiceReference reference) {
+        if (accessControlContext == null) {
+            return bundleContext.getService(reference);
+        } else {
+            return AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                public Object run() {
+                    return bundleContext.getService(reference);
+                }            
+            }, accessControlContext);
+        }
+    }
+    
+    private AccessControlContext createAccessControlContext() {
+        return new AccessControlContext(AccessController.getContext(),
+                new DomainCombiner() {               
+                    public ProtectionDomain[] combine(ProtectionDomain[] arg0,
+                                                      ProtectionDomain[] arg1) {                    
+                        return new ProtectionDomain[] { new ProtectionDomain(null, null) {                        
+                            public boolean implies(Permission permission) {                                                           
+                                return bundleContext.getBundle().hasPermission(permission);
+                            }
+                        } 
+                    };
+                }
+        });
+    }
+    
+    public AccessControlContext getAccessControlContext() {
+        return accessControlContext;
+    }
+    
+    public BlueprintRepository getRepository() {
+        if (repository == null) {
+            repository = new RecipeBuilder(this, tempRecipeIdSpace).createRepository();
+        }
+        return repository;
+    }
+
+    private void processTypeConverters() throws Exception {
+        List<String> typeConverters = new ArrayList<String>();
+        for (Target target : componentDefinitionRegistry.getTypeConverters()) {
+            if (target instanceof ComponentMetadata) {
+                typeConverters.add(((ComponentMetadata) target).getId());
+            } else if (target instanceof RefMetadata) {
+                typeConverters.add(((RefMetadata) target).getComponentId());
+            } else {
+                throw new ComponentDefinitionException("Unexpected metadata for type converter: " + target);
+            }
+        }
+
+        Map<String, Object> objects = repository.createAll(typeConverters);
+        for (String name : typeConverters) {
+            Object obj = objects.get(name);
+            if (obj instanceof Converter) {
+                converter.registerConverter((Converter) obj);
+            } else {
+                throw new ComponentDefinitionException("Type converter " + obj + " does not implement the " + Converter.class.getName() + " interface");
+            }
+        }
+    }
+
+    private void processProcessors() throws Exception {
+        // Instanciate ComponentDefinitionRegistryProcessor and BeanProcessor
+        for (BeanMetadata bean : getMetadata(BeanMetadata.class)) {
+            if (bean instanceof ExtendedBeanMetadata && !((ExtendedBeanMetadata) bean).isProcessor()) {
+                continue;
+            }     
+            
+            Class clazz = null;
+            if (bean instanceof ExtendedBeanMetadata) {
+                clazz = ((ExtendedBeanMetadata) bean).getRuntimeClass();
+            }            
+            if (clazz == null && bean.getClassName() != null) {
+                clazz = loadClass(bean.getClassName());
+            }
+            if (clazz == null) {
+                continue;
+            }
+
+            if (ComponentDefinitionRegistryProcessor.class.isAssignableFrom(clazz)) {
+                Object obj = repository.create(bean.getId());
+                ((ComponentDefinitionRegistryProcessor) obj).process(componentDefinitionRegistry);
+            } else if (Processor.class.isAssignableFrom(clazz)) {
+                Object obj = repository.create(bean.getId());
+                this.processors.add((Processor) obj);
+            } else {
+                continue;
+            }
+            // Update repository with recipes processed by the processors
+            untrackServiceReferences();
+            Repository tmpRepo = new RecipeBuilder(this, tempRecipeIdSpace).createRepository();
+            
+            LOGGER.debug("Updating blueprint repository");
+            
+            for (String name : repository.getNames()) {
+                if (repository.getInstance(name) == null) {
+                    LOGGER.debug("Removing uninstantiated recipe {}", new Object[] { name });
+                    repository.removeRecipe(name);
+                } else {
+                    LOGGER.debug("Recipe {} is already instantiated", new Object[] { name });
+                }
+            }
+            
+            for (String name : tmpRepo.getNames()) {
+                if (repository.getInstance(name) == null) {
+                    LOGGER.debug("Adding new recipe {}", new Object[] { name });
+                    Recipe r = tmpRepo.getRecipe(name);
+                    if (r != null) {
+                        repository.putRecipe(name, r);
+                    }
+                } else {
+                    LOGGER.debug("Recipe {} is already instantiated and cannot be updated", new Object[] { name });
+                }
+            }
+            
+            getSatisfiableDependenciesMap(true);
+            trackServiceReferences();
+        }
+    }
+
+    private Map<String, List<SatisfiableRecipe>> getSatisfiableDependenciesMap() {
+        return getSatisfiableDependenciesMap(false);
+    }
+
+    private Map<String, List<SatisfiableRecipe>> getSatisfiableDependenciesMap(boolean recompute) {
+        synchronized (satisfiablesLock) {
+            if ((recompute || satisfiables == null) && repository != null) {
+                satisfiables = new HashMap<String, List<SatisfiableRecipe>>();
+                for (Recipe r : repository.getAllRecipes()) {
+                    List<SatisfiableRecipe> recipes = repository.getAllRecipes(SatisfiableRecipe.class, r.getName());
+                    if (!recipes.isEmpty()) {
+                        satisfiables.put(r.getName(), recipes);
+                    }
+                }
+            }
+            return satisfiables;
+        }
+    }
+
+    private void trackServiceReferences() {
+        Map<String, List<SatisfiableRecipe>> dependencies = getSatisfiableDependenciesMap();
+        Set<String> satisfiables = new HashSet<String>();
+        for (List<SatisfiableRecipe> recipes : dependencies.values()) {
+            for (SatisfiableRecipe satisfiable : recipes) {
+                if (satisfiables.add(satisfiable.getName())) {
+                    satisfiable.start(this);
+                }
+            }
+        }
+        LOGGER.debug("Tracking service references: {}", satisfiables);
+    }
+    
+    private void untrackServiceReferences() {
+        Map<String, List<SatisfiableRecipe>> dependencies = getSatisfiableDependenciesMap();
+        if (dependencies != null) {
+            Set<String> stopped = new HashSet<String>();
+            for (List<SatisfiableRecipe> recipes : dependencies.values()) {
+                for (SatisfiableRecipe satisfiable : recipes) {
+                    untrackServiceReference(satisfiable, stopped, dependencies);
+                }
+            }
+        }
+    }
+
+    private void untrackServiceReference(SatisfiableRecipe recipe, Set<String> stopped, Map<String, List<SatisfiableRecipe>> dependencies) {
+        if (stopped.add(recipe.getName())) {
+            for (Map.Entry<String, List<SatisfiableRecipe>> entry : dependencies.entrySet()) {
+                if (entry.getValue().contains(recipe)) {
+                    Recipe r = getRepository().getRecipe(entry.getKey());
+                    if (r instanceof SatisfiableRecipe) {
+                        untrackServiceReference((SatisfiableRecipe) r, stopped, dependencies);
+                    }
+                }
+            }
+            recipe.stop();
+        }
+    }
+
+    public void notifySatisfaction(SatisfiableRecipe satisfiable) {
+        LOGGER.debug("Notified satisfaction {} in bundle {}: {}",
+                new Object[] { satisfiable.getName(), bundleContext.getBundle().getSymbolicName(), satisfiable.isSatisfied() });
+        if (state == State.Create || state == State.Created ) {
+            Map<String, List<SatisfiableRecipe>> dependencies = getSatisfiableDependenciesMap();
+            for (Map.Entry<String, List<SatisfiableRecipe>> entry : dependencies.entrySet()) {
+                String name = entry.getKey();
+                ComponentMetadata metadata = componentDefinitionRegistry.getComponentDefinition(name);
+                if (metadata instanceof ServiceMetadata) {
+                    ServiceRecipe reg = (ServiceRecipe) repository.getRecipe(name);
+                    synchronized (reg) {
+                        boolean satisfied = true;
+                        for (SatisfiableRecipe recipe : entry.getValue()) {
+                            if (!recipe.isSatisfied()) {
+                                satisfied = false;
+                                break;
+                            }
+                        }
+                        if (satisfied && !reg.isRegistered()) {
+                            LOGGER.debug("Registering service {} due to satisfied references", name);
+                            reg.register();
+                        } else if (!satisfied && reg.isRegistered()) {
+                            LOGGER.debug("Unregistering service {} due to unsatisfied references", name);
+                            reg.unregister();
+                        }
+                    }
+                }
+            }
+        } else {
+            schedule();
+        }
+    }
+
+    private void instantiateEagerComponents() {
+        List<String> components = new ArrayList<String>();
+        for (String name : componentDefinitionRegistry.getComponentDefinitionNames()) {
+            ComponentMetadata component = componentDefinitionRegistry.getComponentDefinition(name);
+            boolean eager = component.getActivation() == ComponentMetadata.ACTIVATION_EAGER;
+            if (component instanceof BeanMetadata) {
+                BeanMetadata local = (BeanMetadata) component;
+                eager &= MetadataUtil.isSingletonScope(local);
+            }
+            if (eager) {
+                components.add(name);
+            }
+        }
+        LOGGER.debug("Instantiating components: {}", components);
+        try {
+            repository.createAll(components);
+        } catch (ComponentDefinitionException e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new ComponentDefinitionException("Unable to instantiate components", t);
+        }
+    }
+
+    private void registerServices() {
+        services = repository.getAllRecipes(ServiceRecipe.class);
+        for (ServiceRecipe r : services) {
+            List<SatisfiableRecipe> dependencies = getSatisfiableDependenciesMap().get(r.getName());
+            boolean enabled = true;
+            if (dependencies != null) {
+                for (SatisfiableRecipe recipe : dependencies) {
+                    if (!recipe.isSatisfied()) {
+                        enabled = false;
+                        break;
+                    }
+                }
+            }
+            if (enabled) {
+                r.register();
+            }
+        }
+    }
+
+    private void unregisterServices() {
+        if (repository != null) {
+            List<ServiceRecipe> recipes = this.services;
+            this.services = null;
+            if (recipes != null) {
+                for (ServiceRecipe r : recipes) {
+                    r.unregister();
+                }
+            }
+        }
+    }
+
+    private void destroyComponents() {
+        if (repository != null) {
+            repository.destroy();
+        }
+    }
+
+    private String[] getMissingDependencies() {
+        List<String> missing = new ArrayList<String>();
+        Map<String, List<SatisfiableRecipe>> dependencies = getSatisfiableDependenciesMap();
+        Set<SatisfiableRecipe> recipes = new HashSet<SatisfiableRecipe>();
+        for (List<SatisfiableRecipe> deps : dependencies.values()) {
+            for (SatisfiableRecipe recipe : deps) {
+                if (!recipe.isSatisfied()) {
+                    recipes.add(recipe);
+                }
+            }
+        }
+        for (SatisfiableRecipe recipe : recipes) {
+            missing.add(recipe.getOsgiFilter());
+        }
+        return missing.toArray(new String[missing.size()]);
+    }
+    
+    public Set<String> getComponentIds() {
+        Set<String> set = new LinkedHashSet<String>();
+        set.addAll(componentDefinitionRegistry.getComponentDefinitionNames());
+        set.add("blueprintContainer");
+        set.add("blueprintBundle");
+        set.add("blueprintBundleContext");
+        set.add("blueprintConverter");
+        return set;
+    }
+    
+    public Object getComponentInstance(String id) throws NoSuchComponentException {
+        if (repository == null) {
+            throw new NoSuchComponentException(id);
+        }
+        try {
+            LOGGER.debug("Instantiating component {}", id);
+            return repository.create(id);
+        } catch (NoSuchComponentException e) {
+            throw e;
+        } catch (ComponentDefinitionException e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new ComponentDefinitionException("Cound not create component instance for " + id, t);
+        }
+    }
+
+    public ComponentMetadata getComponentMetadata(String id) {
+        ComponentMetadata metadata = componentDefinitionRegistry.getComponentDefinition(id);
+        if (metadata == null) {
+            throw new NoSuchComponentException(id);
+        }
+        return metadata;
+    }
+
+    public <T extends ComponentMetadata> Collection<T> getMetadata(Class<T> clazz) {
+        Collection<T> metadatas = new ArrayList<T>();
+        for (String name : componentDefinitionRegistry.getComponentDefinitionNames()) {
+            ComponentMetadata component = componentDefinitionRegistry.getComponentDefinition(name);
+            getMetadata(clazz, component, metadatas);
+        }
+        metadatas = Collections.unmodifiableCollection(metadatas);
+        return metadatas;
+    }
+
+    private <T extends ComponentMetadata> void getMetadata(Class<T> clazz, Metadata component, Collection<T> metadatas) {
+        if (component == null) {
+            return;
+        }
+        if (clazz.isInstance(component)) {
+            metadatas.add(clazz.cast(component));
+        }
+        if (component instanceof BeanMetadata) {
+            getMetadata(clazz, ((BeanMetadata) component).getFactoryComponent(), metadatas);
+            for (BeanArgument arg : ((BeanMetadata) component).getArguments()) {
+                getMetadata(clazz, arg.getValue(), metadatas);
+            }
+            for (BeanProperty prop : ((BeanMetadata) component).getProperties()) {
+                getMetadata(clazz, prop.getValue(), metadatas);
+            }
+        }
+        if (component instanceof CollectionMetadata) {
+            for (Metadata m : ((CollectionMetadata) component).getValues()) {
+                getMetadata(clazz, m, metadatas);
+            }
+        }
+        if (component instanceof MapMetadata) {
+            for (MapEntry m : ((MapMetadata) component).getEntries()) {
+                getMetadata(clazz, m.getKey(), metadatas);
+                getMetadata(clazz, m.getValue(), metadatas);
+            }
+        }
+        if (component instanceof PropsMetadata) {
+            for (MapEntry m : ((PropsMetadata) component).getEntries()) {
+                getMetadata(clazz, m.getKey(), metadatas);
+                getMetadata(clazz, m.getValue(), metadatas);
+            }
+        }
+        if (component instanceof ServiceReferenceMetadata) {
+            for (ReferenceListener l : ((ServiceReferenceMetadata) component).getReferenceListeners()) {
+                getMetadata(clazz, l.getListenerComponent(), metadatas);
+            }
+        }
+        if (component instanceof ServiceMetadata) {
+            getMetadata(clazz, ((ServiceMetadata) component).getServiceComponent(), metadatas);
+            for (MapEntry m : ((ServiceMetadata) component).getServiceProperties()) {
+                getMetadata(clazz, m.getKey(), metadatas);
+                getMetadata(clazz, m.getValue(), metadatas);
+            }
+            for (RegistrationListener l : ((ServiceMetadata) component).getRegistrationListeners()) {
+                getMetadata(clazz, l.getListenerComponent(), metadatas);
+            }
+        }
+    }
+
+    public Converter getConverter() {
+        return converter;
+    }
+    
+    public ComponentDefinitionRegistryImpl getComponentDefinitionRegistry() {
+        return componentDefinitionRegistry;
+    }
+        
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+    
+    public void destroy() {
+        destroyed = true;
+        eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.DESTROYING, getBundleContext().getBundle(), getExtenderBundle()));
+
+        if (timeoutFuture != null) {
+            timeoutFuture.cancel(false);
+        }
+        if (registration != null) {
+            registration.unregister();
+        }
+        if (handlerSet != null) {
+            handlerSet.removeListener(this);
+            handlerSet.destroy();
+        }
+        unregisterServices();
+        untrackServiceReferences();
+
+        synchronized (running) {
+            while (running.get()) {
+                try {
+                    running.wait();
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        destroyComponents();
+        
+        eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.DESTROYED, getBundleContext().getBundle(), getExtenderBundle()));
+        LOGGER.debug("Blueprint container destroyed: {}", this.bundleContext);
+    }
+
+    public void namespaceHandlerRegistered(URI uri) {
+        if (namespaces != null && namespaces.contains(uri)) {
+            schedule();
+        }
+    }
+
+    public void namespaceHandlerUnregistered(URI uri) {
+        if (namespaces != null && namespaces.contains(uri)) {
+            unregisterServices();
+            untrackServiceReferences();
+            destroyComponents();
+            state = State.WaitForNamespaceHandlers;
+            schedule();
+        }
+    }
+
+}
+



Mime
View raw message