/******************************************************************************
* 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.dependencies.startup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.TypedStringValue;
import org.eclipse.gemini.blueprint.extender.OsgiServiceDependencyFactory;
import org.eclipse.gemini.blueprint.service.exporter.OsgiServicePropertiesResolver;
import org.eclipse.gemini.blueprint.service.importer.DefaultOsgiServiceDependency;
import org.eclipse.gemini.blueprint.service.importer.OsgiServiceDependency;
import org.eclipse.gemini.blueprint.service.importer.support.Availability;
import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceCollectionProxyFactoryBean;
import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceProxyFactoryBean;
import org.eclipse.gemini.blueprint.util.OsgiFilterUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Default mandatory importer dependency factory.
*
* <b>Note:</b> To cope with some of the inconsistencies in the Blueprint spec, lazy mandatory importers will not be
* activated and their configuration will be read directly from the property values (ugh).
*
* @author Costin Leau
*/
public class MandatoryImporterDependencyFactory implements OsgiServiceDependencyFactory {
/** logger */
private static final Log log = LogFactory.getLog(MandatoryImporterDependencyFactory.class);
private static final String AVAILABILITY_PROP = "availability";
private static final String INTERFACES_PROP = "interfaces";
private static final String SERVICE_BEAN_NAME_PROP = "serviceBeanName";
private static final String FILTER_PROP = "filter";
public Collection<OsgiServiceDependency> getServiceDependencies(BundleContext bundleContext,
ConfigurableListableBeanFactory beanFactory) throws BeansException, InvalidSyntaxException, BundleException {
boolean trace = log.isTraceEnabled();
String[] singleBeans =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, OsgiServiceProxyFactoryBean.class,
true, false);
if (trace) {
log.trace("Discovered single proxy importers " + Arrays.toString(singleBeans));
}
String[] collectionBeans =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
OsgiServiceCollectionProxyFactoryBean.class, true, false);
if (trace) {
log.trace("Discovered collection proxy importers " + Arrays.toString(collectionBeans));
}
String[] beans = StringUtils.concatenateStringArrays(singleBeans, collectionBeans);
List<OsgiServiceDependency> beansCollections = new ArrayList<OsgiServiceDependency>(beans.length);
for (int i = 0; i < beans.length; i++) {
if (!isLazy(beanFactory, beans[i])) {
String beanName =
(beans[i].startsWith(BeanFactory.FACTORY_BEAN_PREFIX) ? beans[i]
: BeanFactory.FACTORY_BEAN_PREFIX + beans[i]);
SmartFactoryBean<?> reference = beanFactory.getBean(beanName, SmartFactoryBean.class);
OsgiServiceDependency dependency;
if (reference instanceof OsgiServiceProxyFactoryBean) {
OsgiServiceProxyFactoryBean importer = (OsgiServiceProxyFactoryBean) reference;
dependency =
new DefaultOsgiServiceDependency(beanName, importer.getUnifiedFilter(),
Availability.MANDATORY.equals(importer.getAvailability()));
} else {
OsgiServiceCollectionProxyFactoryBean importer = (OsgiServiceCollectionProxyFactoryBean) reference;
dependency =
new DefaultOsgiServiceDependency(beanName, importer.getUnifiedFilter(),
Availability.MANDATORY.equals(importer.getAvailability()));
}
if (trace)
log.trace("Eager importer " + beanName + " implies dependecy " + dependency);
beansCollections.add(dependency);
} else {
String name = (beans[i].startsWith(BeanFactory.FACTORY_BEAN_PREFIX) ? beans[i].substring(1) : beans[i]);
if (beanFactory.containsBeanDefinition(name)) {
BeanDefinition def = beanFactory.getBeanDefinition(name);
MutablePropertyValues values = def.getPropertyValues();
// figure out if it's a mandatory bean
PropertyValue value = values.getPropertyValue(AVAILABILITY_PROP);
if (value != null && Availability.MANDATORY.equals(value.getValue())) {
String[] intfs = getInterfaces(values.getPropertyValue(INTERFACES_PROP));
String beanName = getString(values.getPropertyValue(SERVICE_BEAN_NAME_PROP));
String filterProp = getString(values.getPropertyValue(FILTER_PROP));
// create filter
Filter filter = createFilter(intfs, beanName, filterProp);
OsgiServiceDependency dependency;
dependency = new DefaultOsgiServiceDependency(name, filter, true);
if (trace)
log.trace("Lazy importer " + beanName + " implies dependecy " + dependency);
beansCollections.add(dependency);
}
} else {
if (trace)
log.trace("Bean " + name
+ " is marked as lazy but does not provide a bean definition; ignoring...");
}
}
}
return beansCollections;
}
private Filter createFilter(String[] intfs, String serviceBeanName, String filter) {
String filterWithClasses = (!ObjectUtils.isEmpty(intfs) ? OsgiFilterUtils.unifyFilter(intfs, filter) : filter);
// add the serviceBeanName/Blueprint component name constraint
String nameFilter;
if (StringUtils.hasText(serviceBeanName)) {
StringBuilder nsFilter = new StringBuilder("(|(");
nsFilter.append(OsgiServicePropertiesResolver.BEAN_NAME_PROPERTY_KEY);
nsFilter.append("=");
nsFilter.append(serviceBeanName);
nsFilter.append(")(");
nsFilter.append(OsgiServicePropertiesResolver.SPRING_DM_BEAN_NAME_PROPERTY_KEY);
nsFilter.append("=");
nsFilter.append(serviceBeanName);
nsFilter.append(")(");
nsFilter.append(OsgiServicePropertiesResolver.BLUEPRINT_COMP_NAME);
nsFilter.append("=");
nsFilter.append(serviceBeanName);
nsFilter.append("))");
nameFilter = nsFilter.toString();
} else {
nameFilter = null;
}
String filterWithServiceBeanName = filterWithClasses;
if (nameFilter != null) {
StringBuilder finalFilter = new StringBuilder();
finalFilter.append("(&");
finalFilter.append(filterWithClasses);
finalFilter.append(nameFilter);
finalFilter.append(")");
filterWithServiceBeanName = finalFilter.toString();
}
return OsgiFilterUtils.createFilter(filterWithServiceBeanName);
}
private String getString(PropertyValue pv) {
if (pv == null)
return "";
Object value = pv.getValue();
if (value == null) {
return "";
}
if (value instanceof TypedStringValue) {
return ((TypedStringValue) value).getValue();
}
return value.toString();
}
private String[] getInterfaces(PropertyValue pv) {
if (pv == null)
return new String[0];
Object value = pv.getValue();
if (value instanceof Collection) {
Collection collection = (Collection) value;
String[] strs = new String[collection.size()];
int index = 0;
for (Object obj : collection) {
if (value instanceof TypedStringValue) {
strs[index] = ((TypedStringValue) value).getValue();
} else {
strs[index] = value.toString();
}
index++;
}
return strs;
} else {
return new String[] { value.toString() };
}
}
private boolean isLazy(ConfigurableListableBeanFactory beanFactory, String beanName) {
String name = (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) ? beanName.substring(1) : beanName);
if (beanFactory.containsBeanDefinition(name)) {
return beanFactory.getBeanDefinition(name).isLazyInit();
}
return false;
}
}