/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.extender.internal.blueprint.activator;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.service.blueprint.container.BlueprintEvent;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.eclipse.gemini.blueprint.blueprint.container.SpringBlueprintContainer;
import org.eclipse.gemini.blueprint.blueprint.container.SpringBlueprintConverter;
import org.eclipse.gemini.blueprint.blueprint.container.SpringBlueprintConverterService;
import org.eclipse.gemini.blueprint.blueprint.container.support.BlueprintContainerServicePublisher;
import org.eclipse.gemini.blueprint.context.BundleContextAware;
import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEvent;
import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener;
import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextFailedEvent;
import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextRefreshedEvent;
import org.eclipse.gemini.blueprint.extender.event.BootstrappingDependenciesEvent;
import org.eclipse.gemini.blueprint.extender.event.BootstrappingDependenciesFailedEvent;
import org.eclipse.gemini.blueprint.extender.internal.activator.OsgiContextProcessor;
import org.eclipse.gemini.blueprint.extender.internal.blueprint.event.EventAdminDispatcher;
import org.eclipse.gemini.blueprint.service.importer.event.OsgiServiceDependencyWaitStartingEvent;
import org.springframework.util.ClassUtils;
/**
* Blueprint specific context processor.
*
* @author Costin Leau
*/
public class BlueprintContainerProcessor implements
OsgiBundleApplicationContextListener<OsgiBundleApplicationContextEvent>, OsgiContextProcessor {
/** logger */
private static final Log log = LogFactory.getLog(BlueprintContainerProcessor.class);
private static final Class<?> ENV_FB_CLASS;
static {
String className = "org.eclipse.gemini.blueprint.blueprint.reflect.internal.metadata.EnvironmentManagerFactoryBean";
ClassLoader loader = OsgiBundleApplicationContextEvent.class.getClassLoader();
ENV_FB_CLASS = ClassUtils.resolveClassName(className, loader);
}
private final EventAdminDispatcher dispatcher;
private final BlueprintListenerManager listenerManager;
private final Bundle extenderBundle;
private final BeanFactoryPostProcessor cycleBreaker;
class BlueprintWaitingEventDispatcher implements ApplicationListener<ApplicationEvent> {
private final BundleContext bundleContext;
private volatile boolean enabled = true;
private volatile boolean initialized = false;
BlueprintWaitingEventDispatcher(BundleContext context) {
this.bundleContext = context;
}
// WAITING event
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextClosedEvent) {
enabled = false;
return;
}
if (event instanceof ContextRefreshedEvent) {
initialized = true;
return;
}
if (event instanceof OsgiServiceDependencyWaitStartingEvent) {
if (enabled) {
OsgiServiceDependencyWaitStartingEvent evt = (OsgiServiceDependencyWaitStartingEvent) event;
String[] filter = new String[] { evt.getServiceDependency().getServiceFilter().toString() };
BlueprintEvent waitingEvent =
new BlueprintEvent(BlueprintEvent.WAITING, bundleContext.getBundle(), extenderBundle,
filter);
listenerManager.blueprintEvent(waitingEvent);
dispatcher.waiting(waitingEvent);
}
return;
}
}
};
public BlueprintContainerProcessor(EventAdminDispatcher dispatcher, BlueprintListenerManager listenerManager,
Bundle extenderBundle) {
this.dispatcher = dispatcher;
this.listenerManager = listenerManager;
this.extenderBundle = extenderBundle;
Class<?> processorClass =
ClassUtils.resolveClassName(
"org.eclipse.gemini.blueprint.blueprint.container.support.internal.config.CycleOrderingProcessor",
BundleContextAware.class.getClassLoader());
cycleBreaker = (BeanFactoryPostProcessor) BeanUtils.instantiate(processorClass);
}
public void postProcessClose(ConfigurableOsgiBundleApplicationContext context) {
BlueprintEvent destroyedEvent =
new BlueprintEvent(BlueprintEvent.DESTROYED, context.getBundle(), extenderBundle);
listenerManager.blueprintEvent(destroyedEvent);
dispatcher.afterClose(destroyedEvent);
}
public void postProcessRefresh(ConfigurableOsgiBundleApplicationContext context) {
BlueprintEvent createdEvent = new BlueprintEvent(BlueprintEvent.CREATED, context.getBundle(), extenderBundle);
listenerManager.blueprintEvent(createdEvent);
dispatcher.afterRefresh(createdEvent);
}
public void postProcessRefreshFailure(ConfigurableOsgiBundleApplicationContext context, Throwable th) {
BlueprintEvent failureEvent =
new BlueprintEvent(BlueprintEvent.FAILURE, context.getBundle(), extenderBundle, th);
listenerManager.blueprintEvent(failureEvent);
dispatcher.refreshFailure(failureEvent);
}
public void preProcessClose(ConfigurableOsgiBundleApplicationContext context) {
BlueprintEvent destroyingEvent =
new BlueprintEvent(BlueprintEvent.DESTROYING, context.getBundle(), extenderBundle);
listenerManager.blueprintEvent(destroyingEvent);
dispatcher.beforeClose(destroyingEvent);
}
public void preProcessRefresh(final ConfigurableOsgiBundleApplicationContext context) {
final BundleContext bundleContext = context.getBundleContext();
// create the ModuleContext adapter
final BlueprintContainer blueprintContainer = createBlueprintContainer(context);
// 1. add event listeners
// add service publisher
context.addApplicationListener(new BlueprintContainerServicePublisher(blueprintContainer, bundleContext));
// add waiting event broadcaster
context.addApplicationListener(new BlueprintWaitingEventDispatcher(context.getBundleContext()));
// 2. add environmental managers
context.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
private static final String BLUEPRINT_BUNDLE = "blueprintBundle";
private static final String BLUEPRINT_BUNDLE_CONTEXT = "blueprintBundleContext";
private static final String BLUEPRINT_CONTAINER = "blueprintContainer";
private static final String BLUEPRINT_EXTENDER = "blueprintExtenderBundle";
private static final String BLUEPRINT_CONVERTER = "blueprintConverter";
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// lazy logger evaluation
Log logger = LogFactory.getLog(context.getClass());
if (!(beanFactory instanceof BeanDefinitionRegistry)) {
logger.warn("Environmental beans will be registered as singletons instead "
+ "of usual bean definitions since beanFactory " + beanFactory
+ " is not a BeanDefinitionRegistry");
}
// add blueprint container bean
addPredefinedBlueprintBean(beanFactory, BLUEPRINT_BUNDLE, bundleContext.getBundle(), logger);
addPredefinedBlueprintBean(beanFactory, BLUEPRINT_BUNDLE_CONTEXT, bundleContext, logger);
addPredefinedBlueprintBean(beanFactory, BLUEPRINT_CONTAINER, blueprintContainer, logger);
// addPredefinedBlueprintBean(beanFactory, BLUEPRINT_EXTENDER, extenderBundle, logger);
addPredefinedBlueprintBean(beanFactory, BLUEPRINT_CONVERTER, new SpringBlueprintConverter(beanFactory),
logger);
// add Blueprint conversion service
// String[] beans = beanFactory.getBeanNamesForType(BlueprintConverterConfigurer.class, false, false);
// if (ObjectUtils.isEmpty(beans)) {
// beanFactory.addPropertyEditorRegistrar(new BlueprintEditorRegistrar());
// }
beanFactory.setConversionService(new SpringBlueprintConverterService(
beanFactory.getConversionService(), beanFactory));
}
private void addPredefinedBlueprintBean(ConfigurableListableBeanFactory beanFactory, String beanName,
Object value, Log logger) {
if (!beanFactory.containsLocalBean(beanName)) {
logger.debug("Registering pre-defined bean named " + beanName);
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
GenericBeanDefinition def = new GenericBeanDefinition();
def.setBeanClass(ENV_FB_CLASS);
ConstructorArgumentValues cav = new ConstructorArgumentValues();
cav.addIndexedArgumentValue(0, value);
def.setConstructorArgumentValues(cav);
def.setLazyInit(false);
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, def);
} else {
beanFactory.registerSingleton(beanName, value);
}
} else {
logger.warn("A bean named " + beanName
+ " already exists; aborting registration of the predefined value...");
}
}
});
// 3. add cycle breaker
context.addBeanFactoryPostProcessor(cycleBreaker);
BlueprintEvent creatingEvent = new BlueprintEvent(BlueprintEvent.CREATING, context.getBundle(), extenderBundle);
listenerManager.blueprintEvent(creatingEvent);
dispatcher.beforeRefresh(creatingEvent);
}
private BlueprintContainer createBlueprintContainer(ConfigurableOsgiBundleApplicationContext context) {
// return new ExceptionHandlingBlueprintContainer(context, bundleContext);
return new SpringBlueprintContainer(context);
}
public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent evt) {
// grace event
if (evt instanceof BootstrappingDependenciesEvent) {
BootstrappingDependenciesEvent event = (BootstrappingDependenciesEvent) evt;
Collection<String> flts = event.getDependencyFilters();
if (flts.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("All dependencies satisfied, not sending Blueprint GRACE event "
+ "with emtpy dependencies from " + event);
}
} else {
String[] filters = flts.toArray(new String[flts.size()]);
BlueprintEvent graceEvent =
new BlueprintEvent(BlueprintEvent.GRACE_PERIOD, evt.getBundle(), extenderBundle, filters);
listenerManager.blueprintEvent(graceEvent);
dispatcher.grace(graceEvent);
}
return;
}
// bootstrapping failure
if (evt instanceof BootstrappingDependenciesFailedEvent) {
BootstrappingDependenciesFailedEvent event = (BootstrappingDependenciesFailedEvent) evt;
Collection<String> flts = event.getDependencyFilters();
String[] filters = flts.toArray(new String[flts.size()]);
BlueprintEvent failureEvent =
new BlueprintEvent(BlueprintEvent.FAILURE, evt.getBundle(), extenderBundle, filters, event
.getFailureCause());
listenerManager.blueprintEvent(failureEvent);
dispatcher.refreshFailure(failureEvent);
return;
}
// created
if (evt instanceof OsgiBundleContextRefreshedEvent) {
postProcessRefresh((ConfigurableOsgiBundleApplicationContext) evt.getApplicationContext());
return;
}
// failure
if (evt instanceof OsgiBundleContextFailedEvent) {
OsgiBundleContextFailedEvent failureEvent = (OsgiBundleContextFailedEvent) evt;
postProcessRefreshFailure(
((ConfigurableOsgiBundleApplicationContext) failureEvent.getApplicationContext()), failureEvent
.getFailureCause());
return;
}
}
}