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