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 21:35:49 UTC

svn commit: r1075139 [13/23] - in /aries/tags/blueprint-0.2-incubating: ./ 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/ bl...

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/RecipeBuilder.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,361 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.aries.blueprint.ComponentDefinitionRegistry;
+import org.apache.aries.blueprint.ExtendedBeanMetadata;
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.PassThroughMetadata;
+import org.apache.aries.blueprint.di.ArrayRecipe;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.apache.aries.blueprint.di.ComponentFactoryRecipe;
+import org.apache.aries.blueprint.di.DependentComponentFactoryRecipe;
+import org.apache.aries.blueprint.di.IdRefRecipe;
+import org.apache.aries.blueprint.di.MapRecipe;
+import org.apache.aries.blueprint.di.PassThroughRecipe;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.RefRecipe;
+import org.apache.aries.blueprint.di.ValueRecipe;
+import org.apache.aries.blueprint.ext.ComponentFactoryMetadata;
+import org.apache.aries.blueprint.ext.DependentComponentFactoryMetadata;
+import org.apache.aries.blueprint.mutable.MutableMapMetadata;
+import org.apache.aries.blueprint.reflect.MetadataUtil;
+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.IdRefMetadata;
+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.NullMetadata;
+import org.osgi.service.blueprint.reflect.PropsMetadata;
+import org.osgi.service.blueprint.reflect.RefMetadata;
+import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
+import org.osgi.service.blueprint.reflect.ReferenceListener;
+import org.osgi.service.blueprint.reflect.ReferenceMetadata;
+import org.osgi.service.blueprint.reflect.RegistrationListener;
+import org.osgi.service.blueprint.reflect.ServiceMetadata;
+import org.osgi.service.blueprint.reflect.ValueMetadata;
+
+/**
+ * TODO: javadoc
+ *
+ * @version $Rev: 985150 $, $Date: 2010-08-13 11:20:09 +0100 (Fri, 13 Aug 2010) $
+ */
+public class RecipeBuilder {
+
+    private final Set<String> names = new HashSet<String>();
+    private final ExtendedBlueprintContainer blueprintContainer;
+    private final ComponentDefinitionRegistry registry;
+    private final IdSpace recipeIdSpace;
+
+    public RecipeBuilder(ExtendedBlueprintContainer blueprintContainer, IdSpace recipeIdSpace) {
+        this.recipeIdSpace = recipeIdSpace;
+        this.blueprintContainer = blueprintContainer;
+        this.registry = blueprintContainer.getComponentDefinitionRegistry();
+    }
+    
+    public BlueprintRepository createRepository() {
+        BlueprintRepository repository = new BlueprintRepository(blueprintContainer);
+        // Create component recipes
+        for (String name : registry.getComponentDefinitionNames()) {
+            ComponentMetadata component = registry.getComponentDefinition(name);
+            Recipe recipe = createRecipe(component);
+            repository.putRecipe(recipe.getName(), recipe);
+        }
+        repository.validate();
+        return repository;
+    }
+
+    public Recipe createRecipe(ComponentMetadata component) {
+
+        // Custom components should be handled before built-in ones
+        // in case we have a custom component that also implements a built-in metadata
+        
+        if (component instanceof DependentComponentFactoryMetadata) { 
+            return createDependentComponentFactoryMetadata((DependentComponentFactoryMetadata) component);
+        } else if (component instanceof ComponentFactoryMetadata) {
+            return createComponentFactoryMetadata((ComponentFactoryMetadata) component);
+        } else if (component instanceof BeanMetadata) {
+            return createBeanRecipe((BeanMetadata) component);
+        } else if (component instanceof ServiceMetadata) {
+            return createServiceRecipe((ServiceMetadata) component);
+        } else if (component instanceof ReferenceMetadata) {
+            return createReferenceRecipe((ReferenceMetadata) component);
+        } else if (component instanceof ReferenceListMetadata) {
+            return createReferenceListRecipe((ReferenceListMetadata) component);
+        } else if (component instanceof PassThroughMetadata) {
+            return createPassThroughRecipe((PassThroughMetadata) component);
+        } else {
+            throw new IllegalStateException("Unsupported component type " + component.getClass());
+        }
+    }
+
+    private Recipe createComponentFactoryMetadata(ComponentFactoryMetadata metadata) {
+        return new ComponentFactoryRecipe<ComponentFactoryMetadata>(
+                metadata.getId(), metadata, blueprintContainer, getDependencies(metadata));
+    }
+    
+    private Recipe createDependentComponentFactoryMetadata(DependentComponentFactoryMetadata metadata) {
+        return new DependentComponentFactoryRecipe(
+                metadata.getId(), metadata, blueprintContainer, getDependencies(metadata));
+    }
+    
+    private List<Recipe> getDependencies(ComponentMetadata metadata) {
+        List<Recipe> deps = new ArrayList<Recipe>();
+        for (String name : metadata.getDependsOn()) {
+            deps.add(new RefRecipe(getName(null), name));
+        }
+        return deps;
+    }
+
+    private Recipe createPassThroughRecipe(PassThroughMetadata passThroughMetadata) {
+        return new PassThroughRecipe(getName(passThroughMetadata.getId()), 
+            passThroughMetadata.getObject());
+    }
+
+    private Recipe createReferenceListRecipe(ReferenceListMetadata metadata) {
+        CollectionRecipe listenersRecipe = null;
+        if (metadata.getReferenceListeners() != null) {
+            listenersRecipe = new CollectionRecipe(getName(null), ArrayList.class);
+            for (ReferenceListener listener : metadata.getReferenceListeners()) {
+                listenersRecipe.add(createRecipe(listener));
+            }
+        }
+        ReferenceListRecipe recipe = new ReferenceListRecipe(getName(metadata.getId()),
+                                                 blueprintContainer,
+                                                 metadata,
+                                                 listenersRecipe,
+                                                 getDependencies(metadata));
+        return recipe;
+    }
+
+    private ReferenceRecipe createReferenceRecipe(ReferenceMetadata metadata) {
+        CollectionRecipe listenersRecipe = null;
+        if (metadata.getReferenceListeners() != null) {
+            listenersRecipe = new CollectionRecipe(getName(null), ArrayList.class);
+            for (ReferenceListener listener : metadata.getReferenceListeners()) {
+                listenersRecipe.add(createRecipe(listener));
+            }
+        }
+        ReferenceRecipe recipe = new ReferenceRecipe(getName(metadata.getId()),
+                                                     blueprintContainer,
+                                                     metadata,
+                                                     listenersRecipe,
+                                                     getDependencies(metadata));
+        return recipe;
+    }
+
+    private Recipe createServiceRecipe(ServiceMetadata serviceExport) {
+        CollectionRecipe listenersRecipe = new CollectionRecipe(getName(null), ArrayList.class);
+        if (serviceExport.getRegistrationListeners() != null) {
+            for (RegistrationListener listener : serviceExport.getRegistrationListeners()) {
+                listenersRecipe.add(createRecipe(listener));
+            }
+        }
+        ServiceRecipe recipe = new ServiceRecipe(getName(serviceExport.getId()),
+                                                 blueprintContainer,
+                                                 serviceExport,
+                                                 getValue(serviceExport.getServiceComponent(), null),
+                                                 listenersRecipe,
+                                                 getServicePropertiesRecipe(serviceExport),
+                                                 getDependencies(serviceExport));
+        return recipe;
+    }
+
+    protected MapRecipe getServicePropertiesRecipe(ServiceMetadata metadata) {
+        List<MapEntry> properties = metadata.getServiceProperties();
+        if (properties != null) {
+            MutableMapMetadata map = MetadataUtil.createMetadata(MutableMapMetadata.class);
+            for (MapEntry e : properties) {
+                map.addEntry(e);
+            }
+            return createMapRecipe(map);
+        } else {
+            return null;
+        }
+    }
+    
+    private Object getBeanClass(BeanMetadata beanMetadata) {
+        if (beanMetadata instanceof ExtendedBeanMetadata) {
+            ExtendedBeanMetadata extBeanMetadata = (ExtendedBeanMetadata) beanMetadata;
+            if (extBeanMetadata.getRuntimeClass() != null) {
+                return extBeanMetadata.getRuntimeClass();
+            }
+        }
+        return beanMetadata.getClassName();        
+    }
+    
+    private boolean allowsFieldInjection(BeanMetadata beanMetadata) {
+        if (beanMetadata instanceof ExtendedBeanMetadata) {
+            return ((ExtendedBeanMetadata) beanMetadata).getFieldInjection();
+        }
+        return false;
+    }
+    
+    private BeanRecipe createBeanRecipe(BeanMetadata beanMetadata) {
+        BeanRecipe recipe = new BeanRecipe(
+                getName(beanMetadata.getId()),
+                blueprintContainer,
+                getBeanClass(beanMetadata),
+                allowsFieldInjection(beanMetadata));
+        // Create refs for explicit dependencies
+        recipe.setExplicitDependencies(getDependencies(beanMetadata));
+        recipe.setPrototype(MetadataUtil.isPrototypeScope(beanMetadata));
+        recipe.setInitMethod(beanMetadata.getInitMethod());
+        recipe.setDestroyMethod(beanMetadata.getDestroyMethod());
+        recipe.setInterceptorLookupKey(beanMetadata);
+        List<BeanArgument> beanArguments = beanMetadata.getArguments();
+        if (beanArguments != null && !beanArguments.isEmpty()) {
+            boolean hasIndex = (beanArguments.get(0).getIndex() >= 0);
+            if (hasIndex) {
+                List<BeanArgument> beanArgumentsCopy = new ArrayList<BeanArgument>(beanArguments);
+                Collections.sort(beanArgumentsCopy, MetadataUtil.BEAN_COMPARATOR);
+                beanArguments = beanArgumentsCopy;
+            }
+            List<Object> arguments = new ArrayList<Object>();
+            List<String> argTypes = new ArrayList<String>();
+            for (BeanArgument argument : beanArguments) {
+                Recipe value = getValue(argument.getValue(), null);
+                arguments.add(value);
+                argTypes.add(argument.getValueType());
+            }
+            recipe.setArguments(arguments);
+            recipe.setArgTypes(argTypes);
+            recipe.setReorderArguments(!hasIndex);
+        }
+        recipe.setFactoryMethod(beanMetadata.getFactoryMethod());
+        if (beanMetadata.getFactoryComponent() != null) {
+            recipe.setFactoryComponent(getValue(beanMetadata.getFactoryComponent(), null));
+        }
+        for (BeanProperty property : beanMetadata.getProperties()) {
+            Recipe value = getValue(property.getValue(), null);
+            recipe.setProperty(property.getName(), value);
+        }
+        return recipe;
+    }
+
+    private Recipe createRecipe(RegistrationListener listener) {
+        BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, ServiceListener.class, false);
+        recipe.setProperty("listener", getValue(listener.getListenerComponent(), null));
+        if (listener.getRegistrationMethod() != null) {
+            recipe.setProperty("registerMethod", listener.getRegistrationMethod());
+        }
+        if (listener.getUnregistrationMethod() != null) {
+            recipe.setProperty("unregisterMethod", listener.getUnregistrationMethod());
+        }
+        recipe.setProperty("blueprintContainer", blueprintContainer);
+        return recipe;
+    }
+
+    private Recipe createRecipe(ReferenceListener listener) {
+        BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, AbstractServiceReferenceRecipe.Listener.class, false);
+        recipe.setProperty("listener", getValue(listener.getListenerComponent(), null));
+        recipe.setProperty("metadata", listener);
+        recipe.setProperty("blueprintContainer", blueprintContainer);
+        return recipe;
+    }
+
+    private Recipe getValue(Metadata v, Object groupingType) {
+        if (v instanceof NullMetadata) {
+            return null;
+        } else if (v instanceof ComponentMetadata) {
+            return createRecipe((ComponentMetadata) v);
+        } else if (v instanceof ValueMetadata) {
+            ValueMetadata stringValue = (ValueMetadata) v;
+            Object type = stringValue.getType();
+            type = (type == null) ? groupingType : type;
+            ValueRecipe vr = new ValueRecipe(getName(null), stringValue, type);
+            return vr;
+        } else if (v instanceof RefMetadata) {
+            // TODO: make it work with property-placeholders?
+            String componentName = ((RefMetadata) v).getComponentId();
+            RefRecipe rr = new RefRecipe(getName(null), componentName);
+            return rr;
+        } else if (v instanceof CollectionMetadata) {
+            CollectionMetadata collectionMetadata = (CollectionMetadata) v;
+            Class cl = collectionMetadata.getCollectionClass();
+            Object type = collectionMetadata.getValueType();
+            if (cl == Object[].class) {
+                ArrayRecipe ar = new ArrayRecipe(getName(null), type);
+                for (Metadata lv : collectionMetadata.getValues()) {
+                    ar.add(getValue(lv, type));
+                }
+                return ar;
+            } else {
+                CollectionRecipe cr = new CollectionRecipe(getName(null), cl != null ? cl : ArrayList.class);
+                for (Metadata lv : collectionMetadata.getValues()) {
+                    cr.add(getValue(lv, type));
+                }
+                return cr;
+            }
+        } else if (v instanceof MapMetadata) {
+            return createMapRecipe((MapMetadata) v);
+        } else if (v instanceof PropsMetadata) {
+            PropsMetadata mapValue = (PropsMetadata) v;
+            MapRecipe mr = new MapRecipe(getName(null), Properties.class);
+            for (MapEntry entry : mapValue.getEntries()) {
+                Recipe key = getValue(entry.getKey(), String.class);
+                Recipe val = getValue(entry.getValue(), String.class);
+                mr.put(key, val);
+            }
+            return mr;
+        } else if (v instanceof IdRefMetadata) {
+            // TODO: make it work with property-placeholders?
+            String componentName = ((IdRefMetadata) v).getComponentId();
+            IdRefRecipe rnr = new IdRefRecipe(getName(null), componentName);
+            return rnr;
+        } else {
+            throw new IllegalStateException("Unsupported value: " + v.getClass().getName());
+        }
+    }
+
+    private MapRecipe createMapRecipe(MapMetadata mapValue) {
+        String keyType = mapValue.getKeyType();
+        String valueType = mapValue.getValueType();
+        MapRecipe mr = new MapRecipe(getName(null), HashMap.class);
+        for (MapEntry entry : mapValue.getEntries()) {
+            Recipe key = getValue(entry.getKey(), keyType);
+            Recipe val = getValue(entry.getValue(), valueType);
+            mr.put(key, val);
+        }
+        return mr;
+    }
+
+    private String getName(String name) {
+        if (name == null) {
+            do {
+                name = "#recipe-" + recipeIdSpace.nextId();
+            } while (names.contains(name) || registry.containsComponentDefinition(name));
+        }
+        names.add(name);
+        return name;
+    }
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,415 @@
+/*
+ * 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.util.*;
+import java.util.concurrent.Callable;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.ExtendedReferenceListMetadata;
+import org.apache.aries.blueprint.ExtendedServiceReferenceMetadata;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.apache.aries.blueprint.utils.DynamicCollection;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.ServiceUnavailableException;
+import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A recipe to create a managed collection of service references
+ *
+ * @version $Rev: 950985 $, $Date: 2010-06-03 14:19:22 +0100 (Thu, 03 Jun 2010) $
+ */
+public class ReferenceListRecipe extends AbstractServiceReferenceRecipe {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceListRecipe.class);
+
+    private final ReferenceListMetadata metadata;
+    private final List<ManagedCollection> collections = new ArrayList<ManagedCollection>();
+    private final DynamicCollection<ServiceDispatcher> storage = new DynamicCollection<ServiceDispatcher>();
+    private final List<ServiceDispatcher> unboundDispatchers = new ArrayList<ServiceDispatcher>();
+    private final Object monitor = new Object();
+    
+    public ReferenceListRecipe(String name,
+                         ExtendedBlueprintContainer blueprintContainer,
+                         ReferenceListMetadata metadata,
+                         CollectionRecipe listenersRecipe,
+                         List<Recipe> explicitDependencies) {
+        super(name, blueprintContainer, metadata, listenersRecipe, explicitDependencies);
+        this.metadata = metadata;
+    }
+
+    @Override
+    protected Object internalCreate() throws ComponentDefinitionException {
+        try {
+            if (explicitDependencies != null) {
+                for (Recipe recipe : explicitDependencies) {
+                    recipe.create();
+                }
+            }
+            ProvidedObject object = new ProvidedObject();
+            addPartialObject(object);
+            // Handle initial references
+            createListeners();
+            updateListeners();
+           
+            return object;
+        } catch (ComponentDefinitionException t) {
+            throw t;
+        } catch (Throwable t) {
+            throw new ComponentDefinitionException(t);
+        }
+    }
+
+    protected void retrack() {
+        List<ServiceReference> refs = getServiceReferences();
+        if (refs != null) {
+            for (ServiceReference ref : refs) {
+                track(ref);
+            }
+        }
+    }
+
+    protected void track(ServiceReference reference) {
+        synchronized (monitor) {
+            try {
+                // ServiceReferences may be tracked at multiple points:
+                //  * first after the collection creation in #internalCreate()
+                //  * in #postCreate() after listeners are created
+                //  * after creation time if a new reference shows up
+                //
+                // In the first step, listeners are not created, so we add
+                // the dispatcher to the unboundDispatchers list.  In the second
+                // step, the dispatcher has already been added to the collection
+                // so we just call the listener.
+                //
+                ServiceDispatcher dispatcher = findDispatcher(reference);
+                if (dispatcher != null) {
+                    if (!unboundDispatchers.remove(dispatcher)) {
+                        return;
+                    }
+                } else {
+                    dispatcher = new ServiceDispatcher(reference);
+                    Set<Class> interfaces = new HashSet<Class>();
+                    if (metadata.getInterface() != null) {
+                        interfaces.add(loadClass(metadata.getInterface()));
+                    }
+                    if (metadata instanceof ExtendedReferenceListMetadata) {
+                        if (((ExtendedServiceReferenceMetadata) metadata).getRuntimeInterface() != null) {
+                            interfaces.add(((ExtendedServiceReferenceMetadata) metadata).getRuntimeInterface());
+                        }
+                        boolean greedy = (((ExtendedReferenceListMetadata) metadata).getProxyMethod() & ExtendedReferenceListMetadata.PROXY_METHOD_GREEDY) != 0;
+                        if (greedy) {
+                            List<String> ifs = Arrays.asList((String[]) reference.getProperty(Constants.OBJECTCLASS));
+                            interfaces.addAll(loadAllClasses(ifs));
+                        }
+                    }
+                    dispatcher.proxy = createProxy(dispatcher, interfaces);
+                    if (!storage.add(dispatcher)) {
+                        dispatcher.destroy();
+                        return;
+                    }
+                }
+                if (listeners != null) {
+                    bind(dispatcher.reference, dispatcher.proxy);                   
+                } else {
+                    unboundDispatchers.add(dispatcher);
+                }
+            } catch (Throwable t) {
+                LOGGER.info("Error tracking new service reference", t);
+            }
+        }
+    }
+
+    protected void untrack(ServiceReference reference) {
+        synchronized (monitor) {
+            ServiceDispatcher dispatcher = findDispatcher(reference);
+            if (dispatcher != null) {
+                unbind(dispatcher.reference, dispatcher.proxy);
+                storage.remove(dispatcher);
+                dispatcher.destroy();
+            }
+        }
+    }
+
+    protected ServiceDispatcher findDispatcher(ServiceReference reference) {
+        for (ServiceDispatcher dispatcher : storage) {
+            if (dispatcher.reference == reference) {
+                return dispatcher;
+            }
+        }
+        return null;
+    }
+
+    protected ManagedCollection getManagedCollection(boolean useReferences) {
+        for (ManagedCollection col : collections) {
+            if (col.references == useReferences) {
+                return col;
+            }
+        }
+        ManagedCollection collection = new ManagedCollection(useReferences, storage);
+        collections.add(collection);
+        return collection;
+    }
+
+    /**
+     * The ServiceDispatcher is used when creating the cglib proxy.
+     * Thic class is responsible for getting the actual service that will be used.
+     */
+    public class ServiceDispatcher implements Callable<Object> {
+
+        public ServiceReference reference;
+        public Object service;
+        public Object proxy;
+        
+        public ServiceDispatcher(ServiceReference reference) throws Exception {
+            this.reference = reference;
+        }
+
+        public synchronized void destroy() {
+            if (reference != null) {
+                reference.getBundle().getBundleContext().ungetService(reference);
+                reference = null;
+                service = null;
+                proxy = null;
+            }
+        }
+
+        public synchronized Object call() throws Exception {
+            if (reference == null) {
+                throw new ServiceUnavailableException("Service is unavailable", getOsgiFilter());
+            }
+            if (service == null) {
+                service = blueprintContainer.getService(reference);
+            }
+            return service;
+        }
+
+    }
+
+    public class ProvidedObject implements AggregateConverter.Convertible {
+
+        public Object convert(ReifiedType type) {
+            LOGGER.debug("Converting ManagedCollection to {}", type);
+            if (!type.getRawClass().isAssignableFrom(List.class)) {
+                throw new ComponentDefinitionException("<reference-list/> can only be converted to a List, not " + type);
+            }
+            int memberType = metadata.getMemberType();            
+            boolean useRef = false;
+            if (type.size() == 1) {
+                useRef = (type.getActualTypeArgument(0).getRawClass() == ServiceReference.class);
+                if ( (useRef && memberType == ReferenceListMetadata.USE_SERVICE_OBJECT) ||
+                     (!useRef && memberType == ReferenceListMetadata.USE_SERVICE_REFERENCE)) {
+                    throw new ComponentDefinitionException("The memeber-type specified is incompatible with generic injection type");
+                }
+            }
+            boolean references;
+            if (memberType == ReferenceListMetadata.USE_SERVICE_REFERENCE) {                
+                references = true;
+            } else if (memberType == ReferenceListMetadata.USE_SERVICE_OBJECT) {
+                references = false;
+            } else {
+                references = useRef;
+            }
+            LOGGER.debug("ManagedCollection references={}", references);
+            return getManagedCollection(references);
+        }
+
+    }
+
+    /**
+     * Base class for managed collections.
+     *
+     * TODO: list iterators should not be supported
+     * TODO: rework the iteration so that if hasNext() has returned false, it will always return false
+     * TODO: implement subList()
+     */
+    public static class ManagedCollection extends AbstractCollection implements List, RandomAccess {
+
+        protected final DynamicCollection<ServiceDispatcher> dispatchers;
+        protected boolean references;
+
+        public ManagedCollection(boolean references, DynamicCollection<ServiceDispatcher> dispatchers) {
+            this.references = references;
+            this.dispatchers = dispatchers;
+            LOGGER.debug("ManagedCollection references={}", references);
+        }
+
+        public boolean addDispatcher(ServiceDispatcher dispatcher) {
+            return dispatchers.add(dispatcher);
+        }
+
+        public boolean removeDispatcher(ServiceDispatcher dispatcher) {
+            return dispatchers.remove(dispatcher);
+        }
+
+        public DynamicCollection<ServiceDispatcher> getDispatchers() {
+            return dispatchers;
+        }
+
+        public Iterator iterator() {
+            return new ManagedListIterator(dispatchers.iterator());
+        }
+
+        public int size() {
+            return dispatchers.size();
+        }
+
+        @Override
+        public boolean add(Object o) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        @Override
+        public boolean addAll(Collection c) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        @Override
+        public void clear() {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        @Override
+        public boolean retainAll(Collection c) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        @Override
+        public boolean removeAll(Collection c) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        public Object get(int index) {
+            return references ? dispatchers.get(index).reference : dispatchers.get(index).proxy;
+        }
+
+        public int indexOf(Object o) {
+            if (o == null) {
+                throw new NullPointerException();
+            }
+            ListIterator e = listIterator();
+            while (e.hasNext()) {
+                if (o.equals(e.next())) {
+                    return e.previousIndex();
+                }
+            }
+            return -1;
+        }
+
+        public int lastIndexOf(Object o) {
+            if (o == null) {
+                throw new NullPointerException();
+            }
+            ListIterator e = listIterator(size());
+            while (e.hasPrevious()) {
+                if (o.equals(e.previous())) {
+                    return e.nextIndex();
+                }
+            }
+            return -1;
+        }
+
+        public ListIterator listIterator() {
+            return listIterator(0);
+        }
+
+        public ListIterator listIterator(int index) {
+            return new ManagedListIterator(dispatchers.iterator(index));
+        }
+
+        public List<ServiceDispatcher> subList(int fromIndex, int toIndex) {
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        public Object set(int index, Object element) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        public void add(int index, Object element) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        public Object remove(int index) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        public boolean addAll(int index, Collection c) {
+            throw new UnsupportedOperationException("This collection is read only");
+        }
+
+        public class ManagedListIterator implements ListIterator {
+
+            protected final ListIterator<ServiceDispatcher> iterator;
+
+            public ManagedListIterator(ListIterator<ServiceDispatcher> iterator) {
+                this.iterator = iterator;
+            }
+
+            public boolean hasNext() {
+                return iterator.hasNext();
+            }
+
+            public Object next() {
+                return references ? iterator.next().reference : iterator.next().proxy;
+            }
+
+            public boolean hasPrevious() {
+                return iterator.hasPrevious();
+            }
+
+            public Object previous() {
+                return references ? iterator.previous().reference : iterator.previous().proxy;
+            }
+
+            public int nextIndex() {
+                return iterator.nextIndex();
+            }
+
+            public int previousIndex() {
+                return iterator.previousIndex();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("This collection is read only");
+            }
+
+            public void set(Object o) {
+                throw new UnsupportedOperationException("This collection is read only");
+            }
+
+            public void add(Object o) {
+                throw new UnsupportedOperationException("This collection is read only");
+            }
+        }
+
+    }
+
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,227 @@
+/*
+ * 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.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.ExtendedServiceReferenceMetadata;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.ServiceUnavailableException;
+import org.osgi.service.blueprint.reflect.ReferenceMetadata;
+import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A recipe to create an unary OSGi service reference.
+ *
+ * TODO: check synchronization / thread safety
+ *
+ * TODO: looks there is a potential problem if the service is unregistered between a call
+ *        to ServiceDispatcher#loadObject() and when the actual invocation finish
+ *
+ * @version $Rev: 950985 $, $Date: 2010-06-03 14:19:22 +0100 (Thu, 03 Jun 2010) $
+ */
+public class ReferenceRecipe extends AbstractServiceReferenceRecipe {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceRecipe.class);
+
+    private final ReferenceMetadata metadata;
+    private Object proxy;
+
+    private volatile ServiceReference trackedServiceReference;
+    private volatile Object trackedService;
+    private final Object monitor = new Object();
+
+    public ReferenceRecipe(String name,
+                           ExtendedBlueprintContainer blueprintContainer,
+                           ReferenceMetadata metadata,
+                           CollectionRecipe listenersRecipe,
+                           List<Recipe> explicitDependencies) {
+        super(name, blueprintContainer, metadata, listenersRecipe, explicitDependencies);
+        this.metadata = metadata;
+    }
+
+    @Override
+    protected Object internalCreate() throws ComponentDefinitionException {
+        try {
+            if (explicitDependencies != null) {
+                for (Recipe recipe : explicitDependencies) {
+                    recipe.create();
+                }
+            }
+            // Create the proxy
+            Set<Class> interfaces = new HashSet<Class>();
+            if (this.metadata.getInterface() != null) {
+                interfaces.add(loadClass(this.metadata.getInterface()));
+            }
+            if (this.metadata instanceof ExtendedServiceReferenceMetadata && ((ExtendedServiceReferenceMetadata) this.metadata).getRuntimeInterface() != null) {
+                interfaces.add(((ExtendedServiceReferenceMetadata) this.metadata).getRuntimeInterface());
+            }
+
+            proxy = createProxy(new ServiceDispatcher(), interfaces);
+
+            // Add partially created proxy to the context
+            ServiceProxyWrapper wrapper = new ServiceProxyWrapper();
+
+            addPartialObject(wrapper);
+
+            // Handle initial references
+            createListeners();
+            updateListeners();            
+
+            // Return a ServiceProxy that can injection of references or proxies can be done correctly
+            return wrapper;
+        } catch (ComponentDefinitionException e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new ComponentDefinitionException(t);
+        }
+    }
+
+    protected void doStop() {
+        synchronized (monitor) {
+            unbind();
+            monitor.notifyAll();
+        }
+    }
+
+    protected void retrack() {
+        ServiceReference ref = getBestServiceReference();
+        if (ref != null) {
+            bind(ref);
+        } else {
+            unbind();
+        }
+    }
+
+    protected void track(ServiceReference ref) {
+        // TODO: make this behavior configurable through a custom attribute
+        // TODO:      policy = sticky | replace
+        synchronized (monitor) {
+            if (trackedServiceReference == null) {
+                retrack();
+            }
+        }
+    }
+
+    protected void untrack(ServiceReference ref) {
+        // TODO: make this behavior configurable through a custom attribute
+        // TODO:      policy = sticky | replace
+        synchronized (monitor) {
+            if (trackedServiceReference == ref) {
+                retrack();
+            }
+        }
+    }
+
+    private void bind(ServiceReference ref) {
+        LOGGER.debug("Binding reference {} to {}", getName(), ref);
+        synchronized (monitor) {
+            if (trackedServiceReference != null) {
+                blueprintContainer.getBundleContext().ungetService(trackedServiceReference);
+            }
+            trackedServiceReference = ref;
+            trackedService = null;
+            monitor.notifyAll();
+            bind(trackedServiceReference, proxy);
+        }
+    }
+
+    private void unbind() {
+        LOGGER.debug("Unbinding reference {}", getName());
+        synchronized (monitor) {
+            if (trackedServiceReference != null) {
+                unbind(trackedServiceReference, proxy);
+                blueprintContainer.getBundleContext().ungetService(trackedServiceReference);
+                trackedServiceReference = null;
+                trackedService = null;
+                monitor.notifyAll();
+            }
+        }
+    }
+
+    private Object getService() throws InterruptedException {
+        synchronized (monitor) {
+            if (isStarted() && trackedServiceReference == null && metadata.getTimeout() > 0
+                    && metadata.getAvailability() == ServiceReferenceMetadata.AVAILABILITY_MANDATORY) {
+                blueprintContainer.getEventDispatcher().blueprintEvent(new BlueprintEvent(BlueprintEvent.WAITING, blueprintContainer.getBundleContext().getBundle(), blueprintContainer.getExtenderBundle(), new String[] { getOsgiFilter() }));
+                monitor.wait(metadata.getTimeout());
+            }
+            if (trackedServiceReference == null) {
+                if (isStarted()) {
+                    LOGGER.info("Timeout expired when waiting for OSGi service {}", getOsgiFilter());
+                    throw new ServiceUnavailableException("Timeout expired when waiting for OSGi service", getOsgiFilter());
+                } else {
+                    throw new ServiceUnavailableException("The Blueprint container is being or has been destroyed", getOsgiFilter());
+                }
+            }
+            if (trackedService == null) {
+                trackedService = blueprintContainer.getService(trackedServiceReference);
+            }
+            if (trackedService == null) {
+                throw new IllegalStateException("getService() returned null for " + trackedServiceReference);
+            }
+            return trackedService;
+        }
+    }
+
+    private ServiceReference getServiceReference() throws InterruptedException {
+        synchronized (monitor) {
+            if (!optional) {
+                getService();
+            }
+            return trackedServiceReference;
+        }
+    }
+
+    public class ServiceDispatcher implements Callable<Object> {
+
+        public Object call() throws Exception {
+            return getService();
+        }
+
+    }
+
+    public class ServiceProxyWrapper implements AggregateConverter.Convertible {
+
+        public Object convert(ReifiedType type) throws Exception {
+            if (type.getRawClass() == ServiceReference.class) {
+                return getServiceReference();
+            } else if (type.getRawClass().isInstance(proxy)) {
+                return proxy;
+            } else {
+                throw new ComponentDefinitionException("Unable to convert to " + type);
+            }
+        }
+
+    }
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/SatisfiableRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/SatisfiableRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/SatisfiableRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/SatisfiableRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.aries.blueprint.di.Recipe;
+
+/**
+ * Interface used to describe an object which can satisfy a constraint or not.
+ *
+ * If the state of the object changes, registered SatisfactionListener objects
+ * will be notified of the change.
+ *
+ * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public interface SatisfiableRecipe extends Recipe {
+
+    /**
+     * A listener that will be notified when the constraint satisfaction changes.
+     *
+     * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+     */
+    public interface SatisfactionListener {
+
+        void notifySatisfaction(SatisfiableRecipe satisfiable);
+
+    }
+
+    void start(SatisfactionListener listener);
+    
+    void stop();
+    
+    boolean isSatisfied();
+
+    String getOsgiFilter();
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceListener.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceListener.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceListener.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceListener.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,107 @@
+/**
+ * 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.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServiceListener {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceListener.class);
+    
+    private Object listener;
+    private String registerMethod;
+    private String unregisterMethod;
+    private ExtendedBlueprintContainer blueprintContainer;
+
+    private List<Method> registerMethods;
+    private List<Method> unregisterMethods;
+    private boolean initialized = false;
+
+    public void setListener(Object listener) {
+        this.listener = listener;
+    }
+
+    public void setRegisterMethod(String method) {
+        this.registerMethod = method;
+    }
+    
+    public void setUnregisterMethod(String method) {
+        this.unregisterMethod = method;
+    }
+    
+    public void setBlueprintContainer(ExtendedBlueprintContainer blueprintContainer) {
+        this.blueprintContainer = blueprintContainer;
+    }
+    
+    public void register(Object service, Map properties) {
+        init(service);
+        invokeMethod(registerMethods, service, properties);
+    }
+
+    public void unregister(Object service, Map properties) {
+        init(service);
+        invokeMethod(unregisterMethods, service, properties);
+    }
+
+    private synchronized void init(Object service) {
+        if (initialized) {
+            return;
+        }
+        Class[] paramTypes = new Class[] { service != null ? service.getClass() : null, Map.class };
+        Class listenerClass = listener.getClass();
+
+        if (registerMethod != null) {
+            registerMethods = ReflectionUtils.findCompatibleMethods(listenerClass, registerMethod, paramTypes);
+            if (registerMethods.size() == 0) {
+                throw new ComponentDefinitionException("No matching methods found for listener registration method: " + registerMethod);
+            }
+            LOGGER.debug("Found register methods: {}", registerMethods);
+        }
+        if (unregisterMethod != null) {
+            unregisterMethods = ReflectionUtils.findCompatibleMethods(listenerClass, unregisterMethod, paramTypes);
+            if (unregisterMethods.size() == 0) {
+                throw new ComponentDefinitionException("No matching methods found for listener unregistration method: " + unregisterMethod);
+            }
+            LOGGER.debug("Found unregister methods: {}", unregisterMethods);
+        }
+        initialized = true;
+    }
+
+    private void invokeMethod(List<Method> methods, Object service, Map properties) {
+        if (methods == null || methods.isEmpty()) {
+            return;
+        }
+        for (Method method : methods) {
+            try {
+                ReflectionUtils.invoke(blueprintContainer.getAccessControlContext(), 
+                                       method, listener, service, properties);
+            } catch (Exception e) {
+                LOGGER.error("Error calling listener method " + method, e);
+            }
+        }
+    }
+
+}
+

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,404 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.aries.blueprint.BlueprintConstants;
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.ServiceProcessor;
+import org.apache.aries.blueprint.di.AbstractRecipe;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.apache.aries.blueprint.di.MapRecipe;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.Repository;
+import org.apache.aries.blueprint.utils.JavaUtils;
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.reflect.RefMetadata;
+import org.osgi.service.blueprint.reflect.ServiceMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A <code>Recipe</code> to export services into the OSGi registry.
+ *
+ * @version $Rev: 990095 $, $Date: 2010-08-27 11:56:22 +0100 (Fri, 27 Aug 2010) $
+ */
+public class ServiceRecipe extends AbstractRecipe {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRecipe.class);
+
+    private final ExtendedBlueprintContainer blueprintContainer;
+    private final ServiceMetadata metadata;
+    private final Recipe serviceRecipe;
+    private final CollectionRecipe listenersRecipe;
+    private final MapRecipe propertiesRecipe;
+    private final List<Recipe> explicitDependencies;
+
+    private Map properties;
+    private final AtomicBoolean registered = new AtomicBoolean();
+    private final AtomicReference<ServiceRegistration> registration = new AtomicReference<ServiceRegistration>();
+    private Map registrationProperties;
+    private List<ServiceListener> listeners;
+    private volatile Object service;
+    
+    public ServiceRecipe(String name,
+                         ExtendedBlueprintContainer blueprintContainer,
+                         ServiceMetadata metadata,
+                         Recipe serviceRecipe,
+                         CollectionRecipe listenersRecipe,
+                         MapRecipe propertiesRecipe,
+                         List<Recipe> explicitDependencies) {
+        super(name);
+        this.prototype = false;
+        this.blueprintContainer = blueprintContainer;
+        this.metadata = metadata;
+        this.serviceRecipe = serviceRecipe;
+        this.listenersRecipe = listenersRecipe;
+        this.propertiesRecipe = propertiesRecipe;
+        this.explicitDependencies = explicitDependencies;
+    }
+    
+    public Recipe getServiceRecipe() {
+        return serviceRecipe;
+    }
+
+    public CollectionRecipe getListenersRecipe() {
+        return listenersRecipe;
+    }
+
+    @Override
+    public List<Recipe> getConstructorDependencies() {
+        List<Recipe> recipes = new ArrayList<Recipe>();
+        if (explicitDependencies != null) {
+            recipes.addAll(explicitDependencies);
+        }
+        return recipes;
+    }
+    
+    public List<Recipe> getDependencies() {
+        List<Recipe> recipes = new ArrayList<Recipe>();
+        if (serviceRecipe != null) {
+            recipes.add(serviceRecipe);
+        }
+        if (listenersRecipe != null) {
+            recipes.add(listenersRecipe);
+        }
+        if (propertiesRecipe != null) {
+            recipes.add(propertiesRecipe);
+        }        
+        recipes.addAll(getConstructorDependencies());        
+        return recipes;
+    }
+
+    protected Object internalCreate() throws ComponentDefinitionException {
+        ServiceRegistrationProxy proxy = new ServiceRegistrationProxy();
+        addPartialObject(proxy);
+        internalGetService(null, null); // null bundle means we don't want to retrieve the actual service when used with a ServiceFactory
+        return proxy;
+    }
+
+    public boolean isRegistered() {
+        return registered.get();
+    }
+
+    public void register() {
+        if (registered.compareAndSet(false, true)) {
+            createExplicitDependencies();
+            
+            Hashtable props = new Hashtable();
+            if (properties == null) {
+                properties = (Map) createRecipe(propertiesRecipe);
+            }
+            props.putAll(properties);
+            if (metadata.getRanking() == 0) {
+                props.remove(Constants.SERVICE_RANKING);
+            } else {
+                props.put(Constants.SERVICE_RANKING, metadata.getRanking());
+            }
+            String componentName = getComponentName();
+            if (componentName != null) {
+                props.put(BlueprintConstants.COMPONENT_NAME_PROPERTY, componentName);
+            } else {
+                props.remove(BlueprintConstants.COMPONENT_NAME_PROPERTY);
+            }
+            for (ServiceProcessor processor : blueprintContainer.getProcessors(ServiceProcessor.class)) {
+                processor.updateProperties(new PropertiesUpdater(), props);
+            }
+
+            registrationProperties = props;
+
+            Set<String> classes = getClasses();
+            String[] classArray = classes.toArray(new String[classes.size()]);
+
+            LOGGER.debug("Registering service {} with interfaces {} and properties {}",
+                         new Object[] { name, classes, props });
+
+            registration.set(blueprintContainer.registerService(classArray, new TriggerServiceFactory(), props));            
+        }
+    }
+
+    public void unregister() {
+        if (registered.compareAndSet(true, false)) {
+            LOGGER.debug("Unregistering service {}", name);
+            // This method needs to allow reentrance, so if we need to make sure the registration is
+            // set to null before actually unregistering the service
+            ServiceRegistration reg = registration.get();
+            if (listeners != null) {
+                LOGGER.debug("Calling listeners for service unregistration");
+                for (ServiceListener listener : listeners) {
+                    listener.unregister(service, registrationProperties);
+                }
+            }
+            if (reg != null) {
+                reg.unregister();
+            }
+            
+            registration.compareAndSet(reg, null);
+        }
+    }
+
+    protected ServiceReference getReference() {
+    	ServiceRegistration reg = registration.get();
+        if (reg == null) {
+            throw new IllegalStateException("Service is not registered");
+        } else {
+            return reg.getReference();
+        }
+    }
+
+    protected void setProperties(Dictionary props) {
+    	ServiceRegistration reg = registration.get();
+        if (reg == null) {
+            throw new IllegalStateException("Service is not registered");
+        } else {
+            reg.setProperties(props);
+            // TODO: set serviceProperties? convert somehow? should listeners be notified of this?
+        }
+    }
+
+
+    protected Object internalGetService() {
+        return internalGetService(blueprintContainer.getBundleContext().getBundle(), null);
+    }
+
+    /**
+     * Create the service object.
+     * We need to synchronize the access to the repository,
+     * but not on this ServiceRecipe instance to avoid deadlock.
+     * When using internalCreate(), no other lock but the on the repository
+     * should be held.
+     *
+     * @param bundle
+     * @param registration
+     * @return
+     */
+    private Object internalGetService(Bundle bundle, ServiceRegistration registration) {
+        LOGGER.debug("Retrieving service for bundle {} and service registration {}", bundle, registration);
+        if (this.service == null) {
+            synchronized (blueprintContainer.getRepository().getInstanceLock()) {
+                if (this.service == null) {
+                    createService();
+                }
+            }
+        }
+        
+        Object service = this.service;
+        // We need the real service ...
+        if (bundle != null) {
+        	if (service instanceof ServiceFactory) {
+        		service = ((ServiceFactory) service).getService(bundle, registration);
+        	}
+        	if (service == null) {
+        		throw new IllegalStateException("service is null");
+        	}
+        	// Check if the service actually implement all the requested interfaces
+        	validateClasses(service);
+        	// We're not really interested in the service, but perform some sanity checks nonetheless
+        } else {
+        	if (!(service instanceof ServiceFactory)) {
+        		// Check if the service actually implement all the requested interfaces
+        		validateClasses(service);
+        	}
+        }
+        
+        return service;
+    }
+
+    private void createService() {
+        try {
+            LOGGER.debug("Creating service instance");
+            service = createRecipe(serviceRecipe);
+            LOGGER.debug("Service created: {}", service);
+            // When the service is first requested, we need to create listeners and call them
+            if (listeners == null) {
+                LOGGER.debug("Creating listeners");
+                if (listenersRecipe != null) {
+                    listeners = (List) createRecipe(listenersRecipe);
+                } else {
+                    listeners = Collections.emptyList();
+                }
+                LOGGER.debug("Listeners created: {}", listeners);
+                if (registered.get()) {
+                    LOGGER.debug("Calling listeners for initial service registration");
+                    for (ServiceListener listener : listeners) {
+                        listener.register(service, registrationProperties);
+                    }
+                } else {
+                    LOGGER.debug("Calling listeners for initial service unregistration");
+                    for (ServiceListener listener : listeners) {
+                        listener.unregister(service, registrationProperties);
+                    }
+                }
+            }
+        } catch (RuntimeException e) {
+            LOGGER.error("Error retrieving service from " + this, e);
+            throw e;
+        }
+    }
+    
+    private void validateClasses(Object service) {
+        // Check if the service actually implement all the requested interfaces
+        if (metadata.getAutoExport() == ServiceMetadata.AUTO_EXPORT_DISABLED) {
+            Set<String> allClasses = new HashSet<String>();
+            ReflectionUtils.getSuperClasses(allClasses, service.getClass());
+            ReflectionUtils.getImplementedInterfaces(allClasses, service.getClass());
+            Set<String> classes = getClasses();
+            classes.removeAll(allClasses);
+            if (!classes.isEmpty()) {
+                throw new ComponentDefinitionException("The service implementation does not implement the required interfaces: " + classes);
+            }
+        }
+    }
+
+    public Object getService(Bundle bundle, ServiceRegistration registration) {
+        /** getService() can get called before registerService() returns with the registration object.
+         *  So we need to set the registration object in case registration listeners call 
+         *  getServiceReference(). 
+         */
+    	this.registration.compareAndSet(null, registration);
+        return internalGetService(bundle, registration);
+    }
+
+    public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+        if (this.service instanceof ServiceFactory) {
+            ((ServiceFactory) this.service).ungetService(bundle, registration, service);
+        }
+    }
+
+    private Set<String> getClasses() {
+        Set<String> classes;
+        switch (metadata.getAutoExport()) {
+            case ServiceMetadata.AUTO_EXPORT_INTERFACES:
+                classes = ReflectionUtils.getImplementedInterfaces(new HashSet<String>(), internalGetService().getClass());
+                break;
+            case ServiceMetadata.AUTO_EXPORT_CLASS_HIERARCHY:
+                classes = ReflectionUtils.getSuperClasses(new HashSet<String>(), internalGetService().getClass());
+                break;
+            case ServiceMetadata.AUTO_EXPORT_ALL_CLASSES:
+                classes = ReflectionUtils.getSuperClasses(new HashSet<String>(), internalGetService().getClass());
+                classes = ReflectionUtils.getImplementedInterfaces(classes, internalGetService().getClass());
+                break;
+            default:
+                classes = new HashSet<String>(metadata.getInterfaces());
+                break;
+        }
+        return classes;
+    }
+
+    private void createExplicitDependencies() {
+        if (explicitDependencies != null) {
+            for (Recipe recipe : explicitDependencies) {
+                createRecipe(recipe);
+            }
+        }
+    }
+    
+    private Object createRecipe(Recipe recipe) {
+        String name = recipe.getName();
+        Repository repo = blueprintContainer.getRepository();
+        if (repo.getRecipe(name) != recipe) {
+            repo.putRecipe(name, recipe);
+        }
+        return repo.create(name);
+    }
+   
+    private String getComponentName() {
+        if (metadata.getServiceComponent() instanceof RefMetadata) {
+            RefMetadata ref = (RefMetadata) metadata.getServiceComponent();
+            return ref.getComponentId();
+        } else {
+            return null;
+        }
+    }
+
+    private class TriggerServiceFactory implements ServiceFactory {
+
+        public Object getService(Bundle bundle, ServiceRegistration registration) {
+            return ServiceRecipe.this.getService(bundle, registration);
+        }
+
+        public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+            ServiceRecipe.this.ungetService(bundle, registration, service);
+        }
+
+    }
+
+    private class ServiceRegistrationProxy implements ServiceRegistration {
+
+        public ServiceReference getReference() {
+            return ServiceRecipe.this.getReference();
+        }
+
+        public void setProperties(Dictionary properties) {
+            ServiceRecipe.this.setProperties(properties);
+        }
+
+        public void unregister() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private class PropertiesUpdater implements ServiceProcessor.ServicePropertiesUpdater {
+
+        public String getId() {
+            return metadata.getId();
+        }
+
+        public void updateProperties(Dictionary properties) {
+            Hashtable table = JavaUtils.getProperties(ServiceRecipe.this.getReference());
+            JavaUtils.copy(table, properties);
+            ServiceRecipe.this.setProperties(table);
+        }        
+    }
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/AbstractRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/AbstractRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/AbstractRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/AbstractRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,130 @@
+/**
+ *
+ * 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.di;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.aries.blueprint.container.GenericType;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+
+public abstract class AbstractRecipe implements Recipe {
+
+    protected final String name;
+    protected boolean prototype = true;
+
+    protected AbstractRecipe(String name) {
+        if (name == null) throw new NullPointerException("name is null");
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isPrototype() {
+        return prototype;
+    }
+
+    public void setPrototype(boolean prototype) {
+        this.prototype = prototype;
+    }
+
+    public final Object create() throws ComponentDefinitionException {
+        // Ensure a container has been set
+        ExecutionContext context = ExecutionContext.Holder.getContext();
+
+        synchronized (context.getInstanceLock()) {
+            // if this recipe has already been executed in this container, return the currently registered value
+            Object obj = context.getPartialObject(name);
+            if (obj != null) {
+                return obj;
+            }
+
+            // execute the recipe
+            context.push(this);
+            try {
+                obj = internalCreate();
+                if (!prototype) {
+                    context.addFullObject(name, obj);
+                }
+                return obj;
+            } finally {
+                Recipe popped = context.pop();
+                if (popped != this) {
+                    //noinspection ThrowFromFinallyBlock
+                    throw new IllegalStateException("Internal Error: recipe stack is corrupt:" +
+                            " Expected " + this + " to be popped of the stack but was " + popped);
+                }
+            }
+        }
+    }
+
+    protected abstract Object internalCreate() throws ComponentDefinitionException;
+
+    protected void addPartialObject(Object obj) {
+        if (!prototype) {                 
+            ExecutionContext.Holder.getContext().addPartialObject(name, obj);
+        }
+    }
+    
+    protected Object convert(Object obj, ReifiedType type) throws Exception {
+        return ExecutionContext.Holder.getContext().convert(obj, type);
+    }
+
+    protected Object convert(Object obj, Type type) throws Exception {
+        return ExecutionContext.Holder.getContext().convert(obj, new GenericType(type));
+    }
+
+    protected Class loadClass(String className) {
+        ReifiedType t = loadType(className, null);
+        return t != null ? t.getRawClass() : null;
+    }
+
+    protected ReifiedType loadType(String typeName) {
+        return loadType(typeName, null);
+    }
+
+    protected ReifiedType loadType(String typeName, ClassLoader fromClassLoader) {
+        if (typeName == null) {
+            return null;
+        }
+        try {
+            return GenericType.parse(typeName, fromClassLoader != null ? fromClassLoader : ExecutionContext.Holder.getContext());
+        } catch (ClassNotFoundException e) {
+            throw new ComponentDefinitionException("Unable to load class " + typeName + " from recipe " + this, e);
+        }
+    }
+
+    public void destroy(Object instance) {
+    }
+
+    public List<Recipe> getConstructorDependencies() {
+        return Collections.emptyList();
+    }
+    
+    public String toString() {
+        return getClass().getSimpleName() + "[" +
+                "name='" + name + '\'' +
+                ']';
+
+    }
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ArrayRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ArrayRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ArrayRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ArrayRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,92 @@
+/**
+ * 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.di;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.ReifiedType;
+
+/**
+ * @version $Rev: 820271 $ $Date: 2009-09-30 14:58:29 +0100 (Wed, 30 Sep 2009) $
+ */
+public class ArrayRecipe extends AbstractRecipe {
+
+    private final List<Recipe> list;
+    private final Object type;
+
+    public ArrayRecipe(String name, Object type) {
+        super(name);
+        this.type = type;
+        this.list = new ArrayList<Recipe>();
+    }
+
+    public List<Recipe> getDependencies() {
+        List<Recipe> nestedRecipes = new ArrayList<Recipe>(list.size());
+        for (Recipe recipe : list) {
+            if (recipe != null) {
+                nestedRecipes.add(recipe);
+            }
+        }
+        return nestedRecipes;
+    }
+
+    protected Object internalCreate() throws ComponentDefinitionException {
+        ReifiedType type;
+        if (this.type instanceof Class) {
+            type = new ReifiedType((Class) this.type);
+        } else if (this.type instanceof String) {
+            type = loadType((String) this.type);
+        } else {
+            type = new ReifiedType(Object.class);
+        }
+
+        // create array instance
+        Object array;
+        try {
+            array = Array.newInstance(type.getRawClass(), list.size());
+        } catch (Exception e) {
+            throw new ComponentDefinitionException("Error while creating array instance: " + type);
+        }
+
+        int index = 0;
+        for (Recipe recipe : list) {
+            Object value;
+            if (recipe != null) {
+                try {
+                    value = convert(recipe.create(), type);
+                } catch (Exception e) {
+                    throw new ComponentDefinitionException("Unable to convert value " + recipe + " to type " + type, e);
+                }
+            } else {
+                value = null;
+            }
+            
+            Array.set(array, index, value);
+            index++;
+        }
+        
+        return array;
+    }
+
+    public void add(Recipe value) {
+        list.add(value);
+    }
+
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CircularDependencyException.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CircularDependencyException.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CircularDependencyException.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CircularDependencyException.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,50 @@
+/**
+ *
+ * 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.di;
+
+import java.util.List;
+
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+
+public class CircularDependencyException extends ComponentDefinitionException {
+    private final List<Recipe> circularDependency;
+
+    public CircularDependencyException(List<Recipe> circularDependency) {
+        super(circularDependency.toString());
+        this.circularDependency = circularDependency;
+    }
+
+    public CircularDependencyException(String message, List<Recipe> circularDependency) {
+        super(message + ": " + circularDependency);
+        this.circularDependency = circularDependency;
+    }
+
+    public CircularDependencyException(String message, Throwable cause, List<Recipe> circularDependency) {
+        super(message + ": " + circularDependency, cause);
+        this.circularDependency = circularDependency;
+    }
+
+    public CircularDependencyException(Throwable cause, List<Recipe> circularDependency) {
+        super(circularDependency.toString(), cause);
+        this.circularDependency = circularDependency;
+    }
+
+    public List<Recipe> getCircularDependency() {
+        return circularDependency;
+    }
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CollectionRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CollectionRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CollectionRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/CollectionRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,111 @@
+/**
+ * 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.di;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.aries.blueprint.utils.ReflectionUtils;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+
+/**
+ * @version $Rev: 896324 $ $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
+ */
+public class CollectionRecipe extends AbstractRecipe {
+
+    private final List<Recipe> list;
+    private final Class typeClass;
+
+    public CollectionRecipe(String name, Class type) {
+        super(name);
+        if (type == null) throw new NullPointerException("type is null");
+        this.typeClass = type;
+        this.list = new ArrayList<Recipe>();
+    }
+
+    public List<Recipe> getDependencies() {
+        List<Recipe> nestedRecipes = new ArrayList<Recipe>(list.size());
+        for (Recipe recipe : list) {
+            if (recipe != null) {
+                nestedRecipes.add(recipe);
+            }
+        }
+        return nestedRecipes;
+    }
+
+    protected Object internalCreate() throws ComponentDefinitionException {
+        Class type = getCollection(typeClass);
+
+        if (!ReflectionUtils.hasDefaultConstructor(type)) {
+            throw new ComponentDefinitionException("Type does not have a default constructor " + type.getName());
+        }
+
+        // create collection instance
+        Object o;
+        try {
+            o = type.newInstance();
+        } catch (Exception e) {
+            throw new ComponentDefinitionException("Error while creating collection instance: " + type.getName());
+        }
+        if (!(o instanceof Collection)) {
+            throw new ComponentDefinitionException("Specified collection type does not implement the Collection interface: " + type.getName());
+        }
+        Collection instance = (Collection) o;
+
+        for (Recipe recipe : list) {
+            Object value;
+            if (recipe != null) {
+                try {
+                    value = recipe.create();
+                } catch (Exception e) {
+                    throw new ComponentDefinitionException("Unable to convert value " + recipe + " to type " + type, e);
+                }
+            } else {
+                value = null;
+            }
+            instance.add(value);
+        }
+        return instance;
+    }
+
+    public void add(Recipe value) {
+        list.add(value);
+    }
+
+    public static Class getCollection(Class type) {
+        if (ReflectionUtils.hasDefaultConstructor(type)) {
+            return type;
+        } else if (SortedSet.class.isAssignableFrom(type)) {
+            return TreeSet.class;
+        } else if (Set.class.isAssignableFrom(type)) {
+            return LinkedHashSet.class;
+        } else if (List.class.isAssignableFrom(type)) {
+            return ArrayList.class;
+        } else if (Queue.class.isAssignableFrom(type)) {
+            return LinkedList.class;
+        } else {
+            return ArrayList.class;
+        }
+    }
+}

Added: aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ComponentFactoryRecipe.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ComponentFactoryRecipe.java?rev=1075139&view=auto
==============================================================================
--- aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ComponentFactoryRecipe.java (added)
+++ aries/tags/blueprint-0.2-incubating/blueprint-core/src/main/java/org/apache/aries/blueprint/di/ComponentFactoryRecipe.java Sun Feb 27 20:35:36 2011
@@ -0,0 +1,63 @@
+/*
+ * 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.di;
+
+import java.util.List;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.ext.ComponentFactoryMetadata;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+
+/**
+ * Pass-through recipe that allows custom bean manager (represented by a ComponentFactoryMetadata instance)
+ * to fit into the container lifecycle.
+ * 
+ * @param <T>
+ */
+public class ComponentFactoryRecipe<T extends ComponentFactoryMetadata> extends AbstractRecipe {
+    private T metadata;
+    private List<Recipe> dependencies;
+    
+    public ComponentFactoryRecipe(String name, T metadata, 
+            ExtendedBlueprintContainer container, List<Recipe> dependencies) {
+        super(name);
+        this.metadata = metadata;
+        this.dependencies = dependencies;
+        metadata.init(container);
+    }
+
+    @Override
+    protected Object internalCreate() throws ComponentDefinitionException {
+        return metadata.create();
+    }
+
+    public List<Recipe> getDependencies() {
+        return dependencies;
+    }
+
+    @Override 
+    public void destroy(Object instance) {
+        metadata.destroy(instance);
+    }
+    
+    protected T getMetadata() {
+        return metadata;
+    }
+
+}