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