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

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

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintRepository.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintRepository.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintRepository.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintRepository.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,383 @@
+/**
+ *
+ * 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.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.di.CircularDependencyException;
+import org.apache.aries.blueprint.di.ExecutionContext;
+import org.apache.aries.blueprint.di.IdRefRecipe;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.RefRecipe;
+import org.apache.aries.blueprint.di.Repository;
+import org.apache.aries.blueprint.di.CollectionRecipe;
+import org.osgi.service.blueprint.container.ReifiedType;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.NoSuchComponentException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default repository implementation
+ */
+public class BlueprintRepository implements Repository, ExecutionContext {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BlueprintRepository.class);
+
+    /**
+     * The blueprint container
+     */
+    private final ExtendedBlueprintContainer blueprintContainer;
+
+    /**
+     * Contains object recipes
+     */
+    private final Map<String, Recipe> recipes = new ConcurrentHashMap<String, Recipe>();
+
+    /**
+     * Contains object instances
+     */
+    private final Map<String, Object> instances = new ConcurrentHashMap<String, Object>();
+
+    /**
+     * Keep track of creation order
+     */
+    private final List<String> creationOrder = new CopyOnWriteArrayList<String>();
+
+    /**
+     * Lock for object instance creation
+     */
+    private final Object instanceLock = new Object();
+
+    /**
+     * Contains partial objects.
+     */
+    private final Map<String, Object> partialObjects = new ConcurrentHashMap<String, Object>();
+
+    /**
+     * Before each recipe is executed it is pushed on the stack.  The
+     * stack is used to detect circular dependencies.
+     */
+    private final LinkedList<Recipe> stack = new LinkedList<Recipe>();
+    
+    public BlueprintRepository(ExtendedBlueprintContainer container) {
+        blueprintContainer = container;
+    }
+    
+    public Object getInstance(String name) {
+        return instances.get(name);
+    }
+
+    public Recipe getRecipe(String name) {
+        return recipes.get(name);
+    }
+
+    public Set<String> getNames() {
+        Set<String> names = new HashSet<String>();
+        names.addAll(recipes.keySet());
+        names.addAll(instances.keySet());
+        return names;
+    }
+
+    public void putRecipe(String name, Recipe recipe) {
+        if (instances.get(name) != null) {
+            throw new ComponentDefinitionException("Name " + name + " is already registered to instance " + instances.get(name));
+        }
+        recipes.put(name, recipe);
+    }
+    
+    public void removeRecipe(String name) {
+        if (instances.get(name) != null)
+            throw new ComponentDefinitionException("Name " + name + " is already instanciated as " + instances.get(name) + " and cannot be removed.");
+
+        recipes.remove(name);
+    }
+
+    private Object convert(String name, Object instance) throws ComponentDefinitionException {
+        try {
+            // Make sure to go through the conversion step in case we have a Convertible object
+            return convert(instance, new ReifiedType(Object.class));
+        } catch (Exception e) {
+            throw new ComponentDefinitionException("Unable to convert instance " + name, e);
+        }
+    }
+        
+    public Object create(String name) throws ComponentDefinitionException {
+        ExecutionContext oldContext = ExecutionContext.Holder.setContext(this);
+        try {
+            Object instance = createInstance(name);                       
+            return convert(name, instance);
+        } finally {
+            ExecutionContext.Holder.setContext(oldContext);
+        }
+    }
+    
+    public Map<String, Object> createAll(Collection<String> names) throws ComponentDefinitionException {
+        ExecutionContext oldContext = ExecutionContext.Holder.setContext(this);
+        try {
+            Map<String, Object> instances = createInstances(names);
+            for (String name : instances.keySet()) {
+                Object obj = instances.get(name);
+                instances.put(name, convert(name, obj));
+            }
+            return instances;
+        } finally {
+            ExecutionContext.Holder.setContext(oldContext);
+        }
+    }
+
+    public <T> List<T> getAllRecipes(Class<T> clazz, String... names) {
+        List<T> recipes = new ArrayList<T>();
+        for (Recipe r : getAllRecipes(names)) {
+            if (clazz.isInstance(r)) {
+                recipes.add(clazz.cast(r));
+            }
+        }
+        return recipes;
+    }
+
+    public Set<Recipe> getAllRecipes(String... names) {
+        ExecutionContext oldContext = ExecutionContext.Holder.setContext(this);
+        try {
+            Set<Recipe> allRecipes = new HashSet<Recipe>();
+            Collection<String> topLevel = names != null && names.length > 0 ? Arrays.asList(names) : recipes.keySet();
+            for (String name : topLevel) {
+                internalGetAllRecipes(allRecipes, getRecipe(name));
+            }
+            return allRecipes;
+        } finally {
+            ExecutionContext.Holder.setContext(oldContext);
+        }
+    }
+
+    /*
+     * This method should not be called directly, only from one of the getAllRecipes() methods.
+     */
+    private void internalGetAllRecipes(Set<Recipe> allRecipes, Recipe r) {
+        if (r != null) {
+            if (allRecipes.add(r)) {
+                for (Recipe c : r.getDependencies()) {
+                    internalGetAllRecipes(allRecipes, c);
+                }
+            }
+        }
+    }
+
+    private Object createInstance(String name) {
+        Object instance = getInstance(name);
+        if (instance == null) {
+            Map <String, Object> instances = createInstances(Arrays.asList(name));
+            instance = instances.get(name); 
+            if (instance == null) {
+                throw new NoSuchComponentException(name);
+            }
+        }
+        return instance;
+    }
+
+    private Map<String, Object> createInstances(Collection<String> names) {
+        // We need to synchronize recipe creation on the repository
+        // so that we don't end up with multiple threads creating the
+        // same instance at the same time.
+        synchronized (instanceLock) {
+            DependencyGraph graph = new DependencyGraph(this);
+            HashMap<String, Object> objects = new LinkedHashMap<String, Object>();
+            for (Map.Entry<String, Recipe> entry : graph.getSortedRecipes(names).entrySet()) {
+                String name = entry.getKey();
+                Object object = instances.get(name);
+                if (object == null) {
+                    Recipe recipe = entry.getValue();
+                    object = recipe.create();
+                }
+                objects.put(name, object);
+            }
+            return objects;
+        }
+    }
+        
+    public void validate() {
+        for (Recipe recipe : getAllRecipes()) {
+            // Check that references are satisfied
+            String ref = null;
+            if (recipe instanceof RefRecipe) {
+                ref = ((RefRecipe) recipe).getIdRef();
+            } else if (recipe instanceof IdRefRecipe) {
+                ref = ((IdRefRecipe) recipe).getIdRef();
+            }
+            if (ref != null && getRecipe(ref) == null) {
+                throw new ComponentDefinitionException("Unresolved ref/idref to component: " + ref);
+            }
+            // Check service
+            if (recipe instanceof ServiceRecipe) {
+                Recipe r = ((ServiceRecipe) recipe).getServiceRecipe();
+                if (r instanceof RefRecipe) {
+                    r = getRecipe(((RefRecipe) r).getIdRef());
+                }
+                if (r instanceof ServiceRecipe) {
+                    throw new ComponentDefinitionException("The target for a <service> element must not be <service> element");
+                }
+                if (r instanceof ReferenceListRecipe) {
+                    throw new ComponentDefinitionException("The target for a <service> element must not be <reference-list> element");
+                }
+                CollectionRecipe listeners = ((ServiceRecipe) recipe).getListenersRecipe();
+                for (Recipe lr : listeners.getDependencies()) {
+                    // The listener recipe is a bean recipe with the listener being set in a property
+                    for (Recipe l : lr.getDependencies()) {
+                        if (l instanceof RefRecipe) {
+                            l = getRecipe(((RefRecipe) l).getIdRef());
+                        }
+                        if (l instanceof ServiceRecipe) {
+                            throw new ComponentDefinitionException("The target for a <registration-listener> element must not be <service> element");
+                        }
+                        if (l instanceof ReferenceListRecipe) {
+                            throw new ComponentDefinitionException("The target for a <registration-listener> element must not be <reference-list> element");
+                        }
+                    }
+                }
+            }
+            // Check references
+            if (recipe instanceof AbstractServiceReferenceRecipe) {
+                CollectionRecipe listeners = ((AbstractServiceReferenceRecipe) recipe).getListenersRecipe();
+                for (Recipe lr : listeners.getDependencies()) {
+                    // The listener recipe is a bean recipe with the listener being set in a property
+                    for (Recipe l : lr.getDependencies()) {
+                        if (l instanceof RefRecipe) {
+                            l = getRecipe(((RefRecipe) l).getIdRef());
+                        }
+                        if (l instanceof ServiceRecipe) {
+                            throw new ComponentDefinitionException("The target for a <reference-listener> element must not be <service> element");
+                        }
+                        if (l instanceof ReferenceListRecipe) {
+                            throw new ComponentDefinitionException("The target for a <reference-listener> element must not be <reference-list> element");
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void destroy() {
+        // destroy objects in reverse creation order
+        List<String> order = new ArrayList<String>(creationOrder);
+        Collections.reverse(order);
+        for (String name : order) {
+            Recipe recipe = recipes.get(name);
+            if (recipe != null) {
+                recipe.destroy(instances.get(name));
+            }
+        }
+        instances.clear();
+        creationOrder.clear();
+    }
+
+    public Object getInstanceLock() {
+        return instanceLock;
+    }
+
+    public void push(Recipe recipe) {
+        if (stack.contains(recipe)) {
+            ArrayList<Recipe> circularity = new ArrayList<Recipe>(stack.subList(stack.indexOf(recipe), stack.size()));
+
+            // remove anonymous nodes from circularity list
+            for (Iterator<Recipe> iterator = circularity.iterator(); iterator.hasNext();) {
+                Recipe item = iterator.next();
+                if (item != recipe && item.getName() == null) {
+                    iterator.remove();
+                }
+            }
+
+            // add ending node to list so a full circuit is shown
+            circularity.add(recipe);
+
+            throw new CircularDependencyException(circularity);
+        }
+        stack.add(recipe);
+    }
+
+    public Recipe pop() {
+        return stack.removeLast();
+    }
+
+    public LinkedList<Recipe> getStack() {
+        return new LinkedList<Recipe>(stack);
+    }
+
+    public boolean containsObject(String name) {
+        return getInstance(name) != null
+                || getRecipe(name) != null;
+    }
+
+    public Object getObject(String name) {
+        Object object = getInstance(name);
+        if (object == null) {
+            object = getRecipe(name);
+        }
+        return object;
+    }
+
+    public void addFullObject(String name, Object object) {
+        if (instances.get(name) != null) {
+            throw new ComponentDefinitionException("Name " + name + " is already registered to instance " + instances.get(name));
+        }
+        instances.put(name, object);
+        creationOrder.add(name); 
+        partialObjects.remove(name);
+    }
+    
+    public void addPartialObject(String name, Object object) {
+        partialObjects.put(name, object);
+    }
+    
+    public Object removePartialObject(String name) {
+        return partialObjects.remove(name);
+    }
+    
+    public Object getPartialObject(String name) {
+        Object obj = partialObjects.get(name);
+        if (obj == null) {
+            obj = getInstance(name);
+        }
+        return obj;
+    }
+
+    public Object convert(Object value, ReifiedType type) throws Exception {
+        return blueprintContainer.getConverter().convert(value, type);
+    }
+    
+    public boolean canConvert(Object value, ReifiedType type) {
+        return blueprintContainer.getConverter().canConvert(value, type);
+    }
+
+    public Class loadClass(String typeName) throws ClassNotFoundException {
+        return blueprintContainer.loadClass(typeName);
+    }
+}

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintThreadFactory.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintThreadFactory.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintThreadFactory.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintThreadFactory.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,38 @@
+/*
+ * 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.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class BlueprintThreadFactory implements ThreadFactory {
+    private final ThreadFactory factory = Executors.defaultThreadFactory();
+    private final AtomicInteger count = new AtomicInteger();
+    private final String name;
+        
+    public BlueprintThreadFactory(String name) {
+        this.name = name;
+    }
+
+    public Thread newThread(Runnable r) {
+        final Thread t = factory.newThread(r);
+        t.setName(name + ": " + count.incrementAndGet());
+        t.setDaemon(true);
+        return t;
+    }
+}

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DependencyGraph.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DependencyGraph.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DependencyGraph.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DependencyGraph.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,188 @@
+/**
+ *
+ * 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.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.blueprint.di.CircularDependencyException;
+import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.di.RefRecipe;
+import org.osgi.service.blueprint.container.NoSuchComponentException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DependencyGraph {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DependencyGraph.class);
+
+    private BlueprintRepository repository;
+    
+    public DependencyGraph(BlueprintRepository repository) {
+        this.repository = repository;        
+    }
+    
+    public LinkedHashMap<String, Recipe> getSortedRecipes(Collection<String> names) {
+        // construct the graph
+        Map<String, Node> nodes = new LinkedHashMap<String, Node>();
+        for (String name : names) {
+            Object object = repository.getObject(name);
+            if (object == null) {
+                throw new NoSuchComponentException(name);
+            }
+            if (object instanceof Recipe) {
+                Recipe recipe = (Recipe) object;
+                if (!recipe.getName().equals(name)) {
+                    throw new RuntimeException("Recipe '" + name + "' returned from the repository has name '" + name + "'");
+                }
+                createNode(name, recipe,  nodes);
+            }
+        }
+
+        // find all initial leaf nodes (and islands)
+        List<Node> sortedNodes = new ArrayList<Node>(nodes.size());
+        LinkedList<Node> leafNodes = new LinkedList<Node>();
+        for (Node n : nodes.values()) {
+            if (n.referenceCount == 0) {
+                // if the node is totally isolated (no in or out refs),
+                // move it directly to the finished list, so they are first
+                if (n.references.size() == 0) {
+                    sortedNodes.add(n);
+                } else {
+                    leafNodes.add(n);
+                }
+            }
+        }
+
+        // pluck the leaves until there are no leaves remaining
+        while (!leafNodes.isEmpty()) {
+            Node node = leafNodes.removeFirst();
+            sortedNodes.add(node);
+            for (Node ref : node.references) {
+                ref.referenceCount--;
+                if (ref.referenceCount == 0) {
+                    leafNodes.add(ref);
+                }
+            }
+        }
+
+        // There are no more leaves so if there are there still
+        // unprocessed nodes in the graph, we have one or more curcuits
+        if (sortedNodes.size() != nodes.size()) {
+            findCircuit(nodes.values().iterator().next(), new ArrayList<Recipe>(nodes.size()));
+            // find circuit should never fail, if it does there is a programming error
+            throw new RuntimeException("Internal Error: expected a CircularDependencyException");
+        }
+        
+        // return the recipes
+        LinkedHashMap<String, Recipe> sortedRecipes = new LinkedHashMap<String, Recipe>();
+        for (Node node : sortedNodes) {
+            sortedRecipes.put(node.name, node.recipe);
+        }
+        
+        return sortedRecipes;
+    }
+
+    private void findCircuit(Node node, ArrayList<Recipe> stack) {
+        if (stack.contains(node.recipe)) {
+            ArrayList<Recipe> circularity = new ArrayList<Recipe>(stack.subList(stack.indexOf(node.recipe), stack.size()));
+
+            // remove anonymous nodes from circularity list
+            for (Iterator<Recipe> iterator = circularity.iterator(); iterator.hasNext();) {
+                Recipe recipe = iterator.next();
+                if (recipe != node.recipe && recipe.getName() == null) {
+                    iterator.remove();
+                }
+            }
+
+            // add ending node to list so a full circuit is shown
+            circularity.add(node.recipe);
+            
+            throw new CircularDependencyException(circularity);
+        }
+
+        stack.add(node.recipe);
+        for (Node reference : node.references) {
+            findCircuit(reference, stack);
+        }
+    }
+
+    private Node createNode(String name, Recipe recipe, Map<String, Node> nodes) {
+        // if node already exists, verify that the exact same recipe instnace is used for both
+        if (nodes.containsKey(name)) {
+            Node node = nodes.get(name);
+            if (node.recipe != recipe) {
+                throw new RuntimeException("The name '" + name +"' is assigned to multiple recipies");
+            }
+            return node;
+        }
+
+        // create the node
+        Node node = new Node();
+        node.name = name;
+        node.recipe = recipe;
+        nodes.put(name, node);
+
+        // link in the references
+        LinkedList<Recipe> constructorRecipes = new LinkedList<Recipe>(recipe.getConstructorDependencies());
+        while (!constructorRecipes.isEmpty()) {
+            Recipe nestedRecipe = constructorRecipes.removeFirst();            
+            if (nestedRecipe instanceof RefRecipe) {
+                nestedRecipe =  nestedRecipe.getDependencies().get(0);
+                String nestedName = nestedRecipe.getName();
+                Node nestedNode = createNode(nestedName, nestedRecipe, nodes);
+                node.referenceCount++;
+                nestedNode.references.add(node);                
+            } else {
+                constructorRecipes.addAll(nestedRecipe.getDependencies());
+            }
+        }
+        
+        return node;
+    }
+
+    private class Node {
+        String name;
+        Recipe recipe;
+        final List<Node> references = new ArrayList<Node>();
+        int referenceCount;
+        
+        public String toString() {
+            StringBuffer buf = new StringBuffer();
+            buf.append("Node[").append(name);
+            if (references.size() > 0) {
+                buf.append(" <- ");
+                Iterator<Node> iter = references.iterator();
+                while(iter.hasNext()) {
+                    buf.append(iter.next().name);
+                    if (iter.hasNext()) {
+                        buf.append(", ");
+                    }
+                }
+            }
+            buf.append("]");
+            return buf.toString();
+        }
+
+    }
+}

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DestroyCallback.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DestroyCallback.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DestroyCallback.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/DestroyCallback.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,26 @@
+/**
+ * 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;
+
+/**
+ * A callback to indicate that a destroy operation has completed
+ */
+public interface DestroyCallback {
+  public void callback(Object key);
+}

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/GenericType.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/GenericType.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/GenericType.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/GenericType.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,253 @@
+/**
+ *
+ * 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.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.aries.blueprint.ExtendedBlueprintContainer;
+import org.apache.aries.blueprint.di.ExecutionContext;
+import org.osgi.framework.Bundle;
+import org.osgi.service.blueprint.container.ReifiedType;
+
+/**
+ * XXXX: Currently, in case of arrays getActualTypeArgument(0) returns something similar to what
+ * Class.getComponentType() does for arrays.  I don't think this is quite right since getActualTypeArgument()
+ * should return the given parameterized type not the component type. Need to check this behavior with the spec.
+ */
+public class GenericType extends ReifiedType {
+
+	private static final GenericType[] EMPTY = new GenericType[0];
+
+    private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
+
+    static {
+        primitiveClasses.put("int", int.class);
+        primitiveClasses.put("short", short.class);
+        primitiveClasses.put("long", long.class);
+        primitiveClasses.put("byte", byte.class);
+        primitiveClasses.put("char", char.class);
+        primitiveClasses.put("float", float.class);
+        primitiveClasses.put("double", double.class);
+        primitiveClasses.put("boolean", boolean.class);
+    }
+
+    private GenericType[] parameters;
+
+	public GenericType(Type type) {
+		this(getConcreteClass(type), parametersOf(type));
+	}
+
+    public GenericType(Class clazz, GenericType... parameters) {
+        super(clazz);
+        this.parameters = parameters;
+    }
+
+    public static GenericType parse(String rawType, final Object loader) throws ClassNotFoundException, IllegalArgumentException {
+        final String type = rawType.trim();
+        // Check if this is an array
+        if (type.endsWith("[]")) {
+            GenericType t = parse(type.substring(0, type.length() - 2), loader);
+            return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
+        }
+        // Check if this is a generic
+        int genericIndex = type.indexOf('<');
+        if (genericIndex > 0) {
+            if (!type.endsWith(">")) {
+                throw new IllegalArgumentException("Can not load type: " + type);
+            }
+            GenericType base = parse(type.substring(0, genericIndex), loader);
+            String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
+            GenericType[] types = new GenericType[params.length];
+            for (int i = 0; i < params.length; i++) {
+                types[i] = parse(params[i], loader);
+            }
+            return new GenericType(base.getRawClass(), types);
+        }
+        // Primitive
+        if (primitiveClasses.containsKey(type)) {
+            return new GenericType(primitiveClasses.get(type));
+        }
+        // Class
+        if (loader instanceof ClassLoader) {
+            return new GenericType(((ClassLoader) loader).loadClass(type));
+        } else if (loader instanceof Bundle) {
+            try {
+              return AccessController.doPrivileged(new PrivilegedExceptionAction<GenericType>() {
+                public GenericType run() throws ClassNotFoundException {
+                  return new GenericType(((Bundle) loader).loadClass(type));
+                }
+              });
+            } catch (PrivilegedActionException pae) {
+              Exception e = pae.getException();
+              if (e instanceof ClassNotFoundException) 
+                throw (ClassNotFoundException) e;
+              else
+                throw (RuntimeException) e;
+            }
+        } else if (loader instanceof ExecutionContext) {
+            return new GenericType(((ExecutionContext) loader).loadClass(type));
+        } else if (loader instanceof ExtendedBlueprintContainer) {
+            return new GenericType(((ExtendedBlueprintContainer) loader).loadClass(type));
+        } else {
+            throw new IllegalArgumentException("Unsupported loader: " + loader);
+        }
+    }
+
+    @Override
+    public ReifiedType getActualTypeArgument(int i) {
+        if (parameters.length == 0) {
+            return super.getActualTypeArgument(i);
+        }
+        return parameters[i];
+    }
+
+    @Override
+    public int size() {
+        return parameters.length;
+    }
+
+    @Override
+    public String toString() {
+        Class cl = getRawClass();
+        if (cl.isArray()) {
+            if (parameters.length > 0) {
+                return parameters[0].toString() + "[]";
+            } else {
+                return cl.getComponentType().getName() + "[]";
+            }
+        }
+        if (parameters.length > 0) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(cl.getName());    
+            sb.append("<");
+            for (int i = 0; i < parameters.length; i++) {
+                if (i > 0) {
+                    sb.append(",");
+                }
+                sb.append(parameters[i].toString());
+            }
+            sb.append(">");   
+            return sb.toString();
+        }
+        return cl.getName();
+    }
+
+    public boolean equals(Object object) {
+        if (!(object instanceof GenericType)) {
+            return false;
+        }
+        GenericType other = (GenericType) object;
+        if (getRawClass() != other.getRawClass()) {
+            return false;
+        }
+        if (parameters == null) {
+            return (other.parameters == null);
+        } else {
+            if (other.parameters == null) {
+                return false;
+            }
+            if (parameters.length != other.parameters.length) {
+                return false;
+            }
+            for (int i = 0; i < parameters.length; i++) {
+                if (!parameters[i].equals(other.parameters[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+    
+    static GenericType[] parametersOf(Type type) {
+		if (type instanceof Class) {
+		    Class clazz = (Class) type;
+		    if (clazz.isArray()) {
+                GenericType t = new GenericType(clazz.getComponentType());
+                if (t.size() > 0) {
+		            return new GenericType[] { t };
+                } else {
+                    return EMPTY;
+                }
+		    } else {
+		        return EMPTY;
+		    }
+		}
+        if (type instanceof ParameterizedType) {
+            ParameterizedType pt = (ParameterizedType) type;
+            Type [] parameters = pt.getActualTypeArguments();
+            GenericType[] gts = new GenericType[parameters.length];
+            for ( int i =0; i<gts.length; i++) {
+                gts[i] = new GenericType(parameters[i]);
+            }
+            return gts;
+        }
+        if (type instanceof GenericArrayType) {
+            return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
+        }
+        if (type instanceof WildcardType) {
+            return EMPTY;
+        }
+        if (type instanceof TypeVariable) {
+            return EMPTY;
+        }
+        throw new IllegalStateException();
+	}
+
+	static Class<?> getConcreteClass(Type type) {
+		Type ntype = collapse(type);
+		if ( ntype instanceof Class )
+			return (Class<?>) ntype;
+
+		if ( ntype instanceof ParameterizedType )
+			return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
+
+		throw new RuntimeException("Unknown type " + type );
+	}
+
+	static Type collapse(Type target) {
+		if (target instanceof Class || target instanceof ParameterizedType ) {
+			return target;
+		} else if (target instanceof TypeVariable) {
+			return collapse(((TypeVariable<?>) target).getBounds()[0]);
+		} else if (target instanceof GenericArrayType) {
+			Type t = collapse(((GenericArrayType) target)
+					.getGenericComponentType());
+			while ( t instanceof ParameterizedType )
+				t = collapse(((ParameterizedType)t).getRawType());
+			return Array.newInstance((Class<?>)t, 0).getClass();
+		} else if (target instanceof WildcardType) {
+			WildcardType wct = (WildcardType) target;
+			if (wct.getLowerBounds().length == 0)
+				return collapse(wct.getUpperBounds()[0]);
+			else
+				return collapse(wct.getLowerBounds()[0]);
+		}
+		throw new RuntimeException("Huh? " + target);
+	}
+
+}

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/IdSpace.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/IdSpace.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/IdSpace.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/IdSpace.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,28 @@
+/**
+ *
+ * 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.concurrent.atomic.AtomicLong;
+
+public class IdSpace {
+    private AtomicLong currentId = new AtomicLong(0);
+    
+    public long nextId() {
+        return currentId.getAndIncrement();
+    }
+}

Added: aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java
URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java?rev=1075147&view=auto
==============================================================================
--- aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java (added)
+++ aries/tags/blueprint-0.3/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java Sun Feb 27 21:05:07 2011
@@ -0,0 +1,119 @@
+/*
+ * 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.net.URI;
+import java.util.Set;
+import java.io.IOException;
+
+import javax.xml.validation.Schema;
+
+import org.apache.aries.blueprint.NamespaceHandler;
+import org.osgi.framework.Bundle;
+import org.xml.sax.SAXException;
+
+/**
+ * Registry of NamespaceHandler.
+ *
+ * @version $Rev: 982158 $, $Date: 2010-08-04 09:32:15 +0100 (Wed, 04 Aug 2010) $
+ */
+public interface NamespaceHandlerRegistry {
+
+    /**
+     * Retrieve the <code>NamespaceHandler</code> for the specified URI. Make sure
+     *
+     * @param uri the namespace identifying the namespace handler
+     * @param bundle the blueprint bundle to be checked for class space consistency
+     *
+     * @return a set of registered <code>NamespaceHandler</code>s compatible with the class space of the given bundle
+     */
+    NamespaceHandlerSet getNamespaceHandlers(Set<URI> uri, Bundle bundle);
+
+    /**
+     * Destroy this registry
+     */
+    void destroy();
+
+    /**
+     * Interface used to managed a set of namespace handlers
+     */
+    public interface NamespaceHandlerSet {
+
+        Set<URI> getNamespaces();
+
+        boolean isComplete();
+
+        /**
+         * Retrieve the NamespaceHandler to use for the given namespace
+         *
+         * @return the NamespaceHandler to use or <code>null</code> if none is available at this time
+         */
+        NamespaceHandler getNamespaceHandler(URI namespace);
+
+        /**
+         * Obtain a schema to validate the XML for the given list of namespaces
+         *
+         * @return the schema to use to validate the XML
+         */
+        Schema getSchema() throws SAXException, IOException;
+
+        /**
+         * Add a new Listener to be called when namespace handlers are registerd or unregistered
+         *
+         * @param listener the listener to register
+         */
+        void addListener(Listener listener);
+
+        /**
+         * Remove a previously registered Listener
+         *
+         * @param listener the listener to unregister
+         */
+        void removeListener(Listener listener);
+
+        /**
+         * Destroy this handler set
+         */
+        void destroy();
+    }
+
+    /**
+     * Interface used to listen to registered or unregistered namespace handlers.
+     *
+     * @see NamespaceHandlerSet#addListener(org.apache.aries.blueprint.container.NamespaceHandlerRegistry.Listener)
+     * @see NamespaceHandlerSet#removeListener(org.apache.aries.blueprint.container.NamespaceHandlerRegistry.Listener) 
+     */
+    public interface Listener {
+
+        /**
+         * Called when a NamespaceHandler has been registered for the specified URI.
+         *
+         * @param uri the URI of the newly registered namespace handler
+         */
+        void namespaceHandlerRegistered(URI uri);
+
+        /**
+         * Called when a NamespaceHandler has been unregistered for the specified URI.
+         *
+         * @param uri the URI of the newly unregistered namespace handler
+         */
+        void namespaceHandlerUnregistered(URI uri);
+
+    }
+}