Here is the first version of the aspect that works in an OSGI environment:
Code:
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.io.Serializable;
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.packageadmin.PackageAdmin;
import org.springframework.beans.factory.annotation.AnnotationBeanWiringInfoResolver;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
public aspect OsgiAnnotationBeanConfigurerAspect extends AbstractInterfaceDrivenDependencyInjectionAspect {
private static final Log LOG = LogFactory.getLog(OsgiAnnotationBeanConfigurerAspect.class);
private ConcurrentHashMap<Bundle, ConfigurableListableBeanFactory> mapOfBeanFactories = new ConcurrentHashMap<Bundle, ConfigurableListableBeanFactory>();
private Map<String, BeanConfigurerSupport> mapOfBeanConfigurers = new HashMap<String, BeanConfigurerSupport>();
static final class Finder extends SecurityManager {
@SuppressWarnings("unchecked")
public Class[] getClassContext() {
return super.getClassContext();
}
}
static ClassLoader finderClassLoader;
static Finder contextFinder;
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
finderClassLoader = OsgiAnnotationBeanConfigurerAspect.class.getClassLoader();
contextFinder = new Finder();
return null;
}
});
}
// spring osgi setters
public void setBundleBeanFactory(BundleContext p_bundleContext, ConfigurableListableBeanFactory p_beanFactory) {
Bundle bundle = p_bundleContext.getBundle();
String bundleName = bundle.getSymbolicName();
LOG.debug(String.format("Saving into internal mapOfBeanFactories bundle: '%s' beanFactory: '%s'", bundleName,
p_beanFactory));
mapOfBeanFactories.put(bundle, p_beanFactory);
BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport();
beanConfigurerSupport.setBeanFactory(p_beanFactory);
beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
mapOfBeanConfigurers.put(bundleName, beanConfigurerSupport);
}
private PackageAdmin m_packageAdmin;
public void setPackageAdmin(PackageAdmin p_packageAdmin) {
m_packageAdmin = p_packageAdmin;
}
// configure bean:
public void configureBean(Object bean) {
Bundle bundle = m_packageAdmin.getBundle(bean.getClass());
String bundleName = bundle.getSymbolicName();
BeanConfigurerSupport beanConfigurerSupport = mapOfBeanConfigurers.get(bundleName);
if (beanConfigurerSupport != null) {
LOG.debug(String.format("configuring bean %s from bundle %s", bean, bundleName));
beanConfigurerSupport.configureBean(bean);
} else {
// We have to go through classloader context
LOG.debug(String.format("BeanConfigurerSupport not found for bean: %s from bundle %s.", bean, bundle
.getSymbolicName()));
boolean configured = false;
Class[] stack = contextFinder.getClassContext();
for (Class klass : stack) {
bundle = m_packageAdmin.getBundle(klass);
if (bundle != null) {
bundleName = bundle.getSymbolicName();
LOG.debug(String.format("class '%s' loaded from bundle '%s'!", klass, bundleName));
beanConfigurerSupport = mapOfBeanConfigurers.get(bundleName);
if (beanConfigurerSupport != null) {
configured = false;
LOG.debug(String.format("About to configure bean '%s' using spring bean configurer from bundle '%s'.",
bean, bundleName));
// will this throw an exception if some properties could not be
// configured?
beanConfigurerSupport.configureBean(bean);
configured = true;
break;
}
}
}
if (!configured) {
LOG.debug("Unable to configure bean '%s'.");
}
}
}
public pointcut inConfigurableBean() : @this(Configurable);
public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);
declare parents: @Configurable * implements ConfigurableObject;
/*
* An intermediary to match preConstructionConfiguration signature (that
* doesn't expose the annotation object)
*/
private pointcut preConstructionConfigurationSupport(Configurable c) : @this(c) && if(c.preConstruction());
/*
* This declaration shouldn't be needed, except for an AspectJ bug
* (https://bugs.eclipse.org/bugs/show_bug.cgi?id=214559)
*/
declare parents: @Configurable Serializable+
implements ConfigurableDeserializationSupport;
}