package org.osgi.cdi.impl.extension; import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.enterprise.event.Event; import javax.enterprise.inject.Instance; import javax.enterprise.util.AnnotationLiteral; import org.osgi.cdi.api.extension.annotation.BundleName; import org.osgi.cdi.api.extension.annotation.BundleVersion; import org.osgi.cdi.api.extension.annotation.Filter; import org.osgi.cdi.api.extension.annotation.Sent; import org.osgi.cdi.api.extension.annotation.Specification; import org.osgi.cdi.api.extension.events.AbstractBundleEvent; import org.osgi.cdi.api.extension.events.AbstractServiceEvent; import org.osgi.cdi.api.extension.events.BundleEvents.BundleInstalled; import org.osgi.cdi.api.extension.events.BundleEvents.BundleLazyActivation; import org.osgi.cdi.api.extension.events.BundleEvents.BundleResolved; import org.osgi.cdi.api.extension.events.BundleEvents.BundleStarted; import org.osgi.cdi.api.extension.events.BundleEvents.BundleStarting; import org.osgi.cdi.api.extension.events.BundleEvents.BundleStopped; import org.osgi.cdi.api.extension.events.BundleEvents.BundleStopping; import org.osgi.cdi.api.extension.events.BundleEvents.BundleUninstalled; import org.osgi.cdi.api.extension.events.BundleEvents.BundleUnresolved; import org.osgi.cdi.api.extension.events.BundleEvents.BundleUpdated; import org.osgi.cdi.api.extension.events.ServiceArrival; import org.osgi.cdi.api.extension.events.ServiceChanged; import org.osgi.cdi.api.extension.events.ServiceDeparture; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; /** * It seems we cannot get the BundleContext in the Extension, so * to fire up OSGi Events (BundleEvent, ServiceEvent and FrameworkEvent) * we need to act here. * * @author Mathieu ANCELIN - SERLI (mathieu.ancelin@serli.com) */ public class ExtensionActivator implements BundleActivator, BundleListener, ServiceListener { private BundleContext context; @Override public void start(BundleContext context) throws Exception { this.context = context; context.addBundleListener(this); context.addServiceListener(this); } @Override public void stop(BundleContext context) throws Exception { } @Override public void bundleChanged(BundleEvent event) { ServiceReference[] references = findReferences(context, Event.class); if (references != null) { for (ServiceReference reference : references) { boolean set = CDIOSGiExtension.currentBundle.get() != null; CDIOSGiExtension.currentBundle.set(reference.getBundle().getBundleId()); Event<Object> e = (Event<Object>) context.getService(reference); try { e.select(BundleEvent.class).fire(event); } catch (Throwable t) { t.printStackTrace(); } Bundle bundle = event.getBundle(); AbstractBundleEvent bundleEvent = null; switch (event.getType()) { case BundleEvent.INSTALLED: bundleEvent = new BundleInstalled(bundle); break; case BundleEvent.LAZY_ACTIVATION: bundleEvent = new BundleLazyActivation(bundle); break; case BundleEvent.RESOLVED: bundleEvent = new BundleResolved(bundle); break; case BundleEvent.STARTED: bundleEvent = new BundleStarted(bundle); break; case BundleEvent.STARTING: bundleEvent = new BundleStarting(bundle); break; case BundleEvent.STOPPED: bundleEvent = new BundleStopped(bundle); break; case BundleEvent.STOPPING: bundleEvent = new BundleStopping(bundle); break; case BundleEvent.UNINSTALLED: bundleEvent = new BundleUninstalled(bundle); break; case BundleEvent.UNRESOLVED: bundleEvent = new BundleUnresolved(bundle); break; case BundleEvent.UPDATED: bundleEvent = new BundleUpdated(bundle); break; } if (bundleEvent != null) { fireAllEvent(bundleEvent, e); } if (!set) { CDIOSGiExtension.currentBundle.remove(); } } } } private ServiceReference[] findReferences(BundleContext context, Class<?> type) { ServiceReference[] references = null; try { references = context.getServiceReferences(type.getName(), null); } catch (InvalidSyntaxException e) { // Ignored } return references; } @Override public void serviceChanged(ServiceEvent event) { ServiceReference[] references = findReferences(context, Instance.class); if (references != null) { for (ServiceReference reference : references) { boolean set = CDIOSGiExtension.currentBundle.get() != null; CDIOSGiExtension.currentBundle.set(reference.getBundle().getBundleId()); Instance<Object> instance = (Instance<Object>) context.getService(reference); Event<Object> e = instance.select(Event.class).get(); try { e.select(ServiceEvent.class).fire(event); } catch (Throwable t) { t.printStackTrace(); } ServiceReference ref = event.getServiceReference(); AbstractServiceEvent serviceEvent = null; switch (event.getType()) { case ServiceEvent.MODIFIED: serviceEvent = new ServiceChanged(ref, context); break; case ServiceEvent.REGISTERED: serviceEvent = new ServiceArrival(ref, context); break; case ServiceEvent.UNREGISTERING: serviceEvent = new ServiceDeparture(ref, context); break; } if (serviceEvent != null) { fireAllEvent(serviceEvent, e, instance); } if (!set) { CDIOSGiExtension.currentBundle.remove(); } } } } private void fireAllEvent(AbstractServiceEvent event, Event broadcaster, Instance<Object> instance) { List<Class<?>> classes = event.getServiceClasses(); Class eventClass = event.getClass(); for (Class<?> clazz : classes) { try { broadcaster.select(eventClass, filteredServicesQualifiers(event, new SpecificationAnnotation(clazz), instance)) .fire(event); } catch (Throwable t) { t.printStackTrace(); } } } private Annotation[] filteredServicesQualifiers(AbstractServiceEvent event, SpecificationAnnotation specific, Instance<Object> instance) { Set<Annotation> eventQualifiers = new HashSet<Annotation>(); eventQualifiers.add(specific); CDIOSGiExtension ext = instance.select(CDIOSGiExtension.class).get(); for (Annotation anno : ext.getObservers()) { String value = ((Filter) anno).value(); try { org.osgi.framework.Filter filter = context.createFilter(value); if (filter.match(event.getRef())) { eventQualifiers.add(new FilterAnnotation(value)); } } catch (InvalidSyntaxException ex) { //ex.printStackTrace(); } } return eventQualifiers.toArray(new Annotation[eventQualifiers.size()]); } private void fireAllEvent(AbstractBundleEvent event, Event broadcaster) { try { broadcaster.select(event.getClass(), new BundleNameAnnotation(event.getSymbolicName()), new BundleVersionAnnotation(event.getVersion().toString())) .fire(event); } catch (Throwable t) { t.printStackTrace(); } } private static class BundleNameAnnotation extends AnnotationLiteral<BundleName> implements BundleName { private final String value; public BundleNameAnnotation(String value) { this.value = value; } @Override public String value() { return value; } @Override public Class<? extends Annotation> annotationType() { return BundleName.class; } } private static class BundleVersionAnnotation extends AnnotationLiteral<BundleVersion> implements BundleVersion { private final String value; public BundleVersionAnnotation(String value) { this.value = value; } @Override public String value() { return value; } @Override public Class<? extends Annotation> annotationType() { return BundleVersion.class; } } public static class SpecificationAnnotation extends AnnotationLiteral<Specification> implements Specification { private final Class value; public SpecificationAnnotation(Class value) { this.value = value; } @Override public Class value() { return value; } @Override public Class<? extends Annotation> annotationType() { return Specification.class; } } public static class SentAnnotation extends AnnotationLiteral<Sent> implements Sent { @Override public Class<? extends Annotation> annotationType() { return Sent.class; } } public static class FilterAnnotation extends AnnotationLiteral<Filter> implements Filter { private final String value; public FilterAnnotation(String value) { this.value = value; } @Override public Class<? extends Annotation> annotationType() { return Filter.class; } @Override public String value() { return value; } } }