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);
+
+ }
+}