Java tutorial
/**************************************************************** * 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.james.container.spring.osgi; import java.net.URL; import java.util.Enumeration; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.james.container.spring.lifecycle.ConfigurationProvider; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ApplicationContext; import org.springframework.osgi.context.BundleContextAware; import org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext; import org.springframework.osgi.service.exporter.OsgiServicePropertiesResolver; import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean; /** * This {@link BundleListener} use the extender pattern to scan all loaded * bundles if a class name with a given name is present. If so it register in * the {@link BeanDefinitionRegistry} and also register it to the OSG-Registry via an {@link OsgiServiceFactoryBean} * */ public abstract class AbstractBundleTracker implements BeanFactoryAware, BundleListener, BundleContextAware, InitializingBean, DisposableBean { private BundleContext context; private String configuredClass; private volatile OsgiServiceFactoryBean osgiFactoryBean; private BeanFactory factory; private final Logger logger = LoggerFactory.getLogger(AbstractBundleTracker.class); @Override public void setBeanFactory(BeanFactory factory) throws BeansException { this.factory = factory; } @Override public void setBundleContext(BundleContext context) { this.context = context; } @Override public void bundleChanged(BundleEvent event) { Bundle b = event.getBundle(); // Check if the event was fired for this class if (b.equals(this.context.getBundle())) { return; } switch (event.getType()) { case BundleEvent.STARTED: Enumeration<?> entrs = b.findEntries("/", "*.class", true); if (entrs != null) { // Loop over all the classes while (entrs.hasMoreElements()) { URL e = (URL) entrs.nextElement(); String file = e.getFile(); String className = file.replaceAll("/", ".").replaceAll(".class", "").replaceFirst(".", ""); if (className.equals(configuredClass)) { try { BeanFactory bFactory = getBeanFactory(b.getBundleContext()); Class<?> clazz = getServiceClass(); // Create the definition and register it BeanDefinitionRegistry registry = (BeanDefinitionRegistry) bFactory; BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(className) .getBeanDefinition(); registry.registerBeanDefinition(getComponentName(), def); // register the bean as service in the OSGI-Registry osgiFactoryBean = new OsgiServiceFactoryBean(); osgiFactoryBean.setTargetBeanName(getComponentName()); osgiFactoryBean.setBeanFactory(bFactory); osgiFactoryBean.setBundleContext(b.getBundleContext()); osgiFactoryBean.setInterfaces(new Class[] { clazz }); osgiFactoryBean.afterPropertiesSet(); logger.debug("Registered " + configuredClass + " in the OSGI-Registry with interface " + clazz.getName()); } catch (Exception e1) { logger.error("Unable to register " + configuredClass + " in the OSGI-Registry", e1); } } } } break; case BundleEvent.STOPPED: // check if we need to destroy the OsgiFactoryBean. This also include the unregister from the OSGI-Registry if (osgiFactoryBean != null) { osgiFactoryBean.destroy(); osgiFactoryBean = null; logger.debug("Unregistered " + configuredClass + " in the OSGI-Registry with interface " + getServiceClass().getName()); } break; default: break; } } /** * Return the {@link BeanFactory} for the given {@link BundleContext}. If none can be found we just create a new {@link AbstractDelegatedExecutionApplicationContext} and return the {@link BeanFactory} of it * * * @param bundleContext * @return factory * @throws Exception */ private BeanFactory getBeanFactory(BundleContext bundleContext) throws Exception { final String filter = "(" + OsgiServicePropertiesResolver.BEAN_NAME_PROPERTY_KEY + "=" + bundleContext.getBundle().getSymbolicName() + ")"; final ServiceReference<?>[] applicationContextRefs = bundleContext .getServiceReferences(ApplicationContext.class.getName(), filter); // Check if we found an ApplicationContext. If not create one if (applicationContextRefs == null || applicationContextRefs.length != 1) { // Create a new context which just serve as registry later AbstractDelegatedExecutionApplicationContext context = new AbstractDelegatedExecutionApplicationContext() { }; context.setBundleContext(bundleContext); context.setPublishContextAsService(true); context.refresh(); return context.getBeanFactory(); } else { return ((ApplicationContext) bundleContext.getService(applicationContextRefs[0])) .getAutowireCapableBeanFactory(); } } @Override public void afterPropertiesSet() throws Exception { ConfigurationProvider confProvider = factory.getBean(ConfigurationProvider.class); HierarchicalConfiguration config = confProvider.getConfiguration(getComponentName()); // Get the configuration for the class configuredClass = config.getString("[@class]"); if (context != null) { context.addBundleListener(this); } } @Override public void destroy() throws Exception { // Its time to unregister the listener so we are sure resources are released if (context != null) { context.removeBundleListener(this); } } /** * Return the name of the component * * @return name */ protected abstract String getComponentName(); /** * Return the class which will be used to expose the service in the OSGI * registry * * @return sClass */ protected abstract Class<?> getServiceClass(); }